- 类初始化函数中的默认参数bug
默认参数如果是不可变类型, 比如基础数据类型 int str 和不可变 tuple等, 这些是不会出bug的, 而用到可变默认参数, 就会出现幽灵般的bug, 看下面代码
class HauntedBus:
def __init__(self, passengers = []):
self.passengers = passengers
def pick(self, name):
self.passengers.append(name)
def drop(self, name):
self.passengers.remove(name)
def __repr__(self):
return str(self.passengers)
if __name__ == '__main__':
bus1 = HauntedBus(['Alice', 'Bill'])
print('bus1 is {}'.format(bus1))
bus1.pick('Charlie')
bus1.drop('Alice')
print('bus1 is {}'.format(bus1))
bus2 = HauntedBus()
bus2.pick('Charlie')
print('bus2 is {}'.format(bus2))
bus3 = HauntedBus()
print('bus3 is {}'.format(bus3))
print(dir(HauntedBus.__init__))
print(HauntedBus.__init__.__defaults__)
bus2.pick('lucy')
print(HauntedBus.__init__.__defaults__)
运行结果:
bus1 is ['Alice', 'Bill']
bus1 is ['Bill', 'Charlie']
bus2 is ['Charlie']
bus3 is ['Charlie']
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
(['Charlie'],)
(['Charlie', 'lucy'],)
Process finished with exit code 0
在载入模块 HauntedBus 的时候, 就已经创建了默认参数passengers, 保存在 HauntedBus._init _._defaults _ 中, 由于是类属性而不是 实例属性, 所以只会保存一份, 并且以引用方式赋值, 所以会有 N个实例共用一个 列表的情况, 导致数据混乱.
函数是一等对象, 同理会有一样的问题, 一般默认参数都使用 none 之类的不可变参数, 并用if来判断是否传参后 再进行创建 列表