可变默认参数陷阱

出现的原因

首先,我们先来看现象,再来分析原因。

 

我创建了两个购物车的实例且只给其中的一个对象的items里,添加了小米手机这一个值,但是为什么两个对象的实例变量里都有同样的值呢?

 


 

核心原因

核心原因:Python解释器处理代码的时候会按 定义阶段调用阶段两步走:

1. 定义阶段(加载类 / 方法时)

当解释器读到 def __init__(self, owner, items=[], total_price=0): 时,会:

  1. 为默认参数 items=[] 创建一个全局唯一的空列表对象(内存地址固定);

  2. 把这个列表对象绑定到 items 默认参数上。

2. 调用阶段(创建实例时)

每次执行 ShoppingCart("小明")/ShoppingCart("小红") 时:

  1. 因为没传 items 参数,会复用定义阶段创建的那个全局列表;

  2. 所有实例的 self.items 都指向同一个内存地址的列表

  3. 所以修改任意一个实例的 items,其他实例的 items 都会跟着变。

 


内存地址验证

如果听起来还是比较模糊的话,我们用更直观的内存地址验证一下,就能看到本质:

两个实例的 items 指向同一个内存地址,自然会共享数据。

 

处理方法

解决思路:默认值用不可变对象(比如 None),在方法内部创建新的可变对象

 

永远不要用列表、字典等可变对象作为方法的默认参数,用 None 代替,在内部创建新对象就不会踩坑了!!!!

这里在复习一下,不可变对象有哪些,其实就是strtuple ,这是我们常用的!