现在我们有一个函数,接受几个参数,其中一个参数是一个列表,如下:
def foo(a, bar=[]):
bar.append(a)
print(bar)
请问这个函数有错误吗?貌似没有,先运行试试:
foo(1)
# 输出
[1] # 没问题
foo(1)
# 输出
[1, 1] # 为什么会有两个1???
为什么在第二次运行foo(1)
的时候bar会有两个1呢?这是因为在同一环境下,多次运行同一函数,函数参数仅初始化一次,因此对于这些可变的变量,每运行一次函数其值便会进行相应的更改。
下面对foo()
函数进行一个修改:
def foo(a, bar=None):
bar = [] if bar is None else bar
bar.append(a)
print(bar)
foo(1)
# [1]
foo(1)
# [1]
这时候每一次运行函数时,只要不是指定bar,bar都会被重新赋值为空列表。我们的问题也得到解决。
下面我们在来看看类中的相似情况:
class Bag:
def __init__(self, contents=[]):
self._contents = contents
def add(self, something):
self._contents.append(something)
# 第一次实例化类
A = Bag()
A.add(1)
print(A._contents)
# [1]
# 第二次实例化类
B = Bag()
B.add(2)
print(B._contents)
# [1, 2]
这里出现了与上面相同的情况,我们可以用相同的方法来解决:
class Bug:
def __init__(self, contents=None):
if contents is None:
contents = []
self._contents = contents
def add(self, something):
self._contents.append(something)
# 第一次实例化
A = Bug()
A.add(1)
print(A._contents)
# [1]
# 第二次实例化
B = Bug()
B.add(2)
print(B._contents)
# [2]
除了上面这种解决办法外,还有另一种解决办法,这种方法需要借助于attr
库:
import attr
@attr.s
class A(object):
_contents = attr.ib(default=attr.Factory(list))
def add(self, x):
self._contents.append(x)
a = A()
a.add(6)
print(a._contents)
# [6]
b = A()
b.add(666)
print(b._contents)
# [666]