我想创建一个类的实例,其中包含默认为空的列表;而不是以后将此列表设置为最终完整列表,我想连续添加项目。这是一段示例代码:
#!/usr/bin/python
class test:
def __init__(self, lst=[], intg=0):
self.lista = lst
self.integer = intg
name_dict = {}
counter = 0
for name in ('Anne', 'Leo', 'Suzy'):
counter += 1
name_dict[name] = test()
name_dict[name].integer += 1
name_dict[name].lista.append(counter)
print name, name_dict[name].integer, name_dict[name].lista
当我运行上述程序时,我希望得到
安妮1 [1]
狮子座1 [2]
Suzy 1 [3]
因为我假设lista
始终被初始化为空列表。
我得到的是:
安妮1 [1]
狮子座1 [1,2]
Suzy 1 [1,2,3]
如果我将self.lista = lst
替换为self.lista = []
,它可以正常工作,就像我将行name_dict[name].lista = []
添加到for循环一样。
为什么保留先前对象列表的内容,但integer
的值不是?我对Python很陌生,所以如果有人可以向我指出我的想法/假设误入歧途会很棒。
提前感谢您的回复。
答案 0 :(得分:12)
使用可变对象作为默认值是一个非常糟糕的主意,就像在此处一样:
def __init__(self, lst=[], intg=0):
# ...
将其更改为:
def __init__(self, lst=None, intg=0):
if lst is None:
lst = []
# ...
你的版本不起作用的原因是在定义函数时只创建一个空列表,而不是每次调用函数时都会创建。
在某些Python实现中,您可以通过检查func_defaults
的值来查看函数默认值的值:
print test.__init__.func_defaults
name_dict[name] = test()
# ...
输出:
([],) Anne 1 [1] ([1],) Leo 1 [1, 2] ([1, 2],) Suzy 1 [1, 2, 3]
答案 1 :(得分:4)
问题出在这一行:
def __init__(self, lst=[], intg=0):
您不应将列表用作默认参数。在没有指定__init__
的情况下调用第一次lst
时,Python解释器将定义一个空列表[]
。如果未指定lst
,则对该功能的后续调用将在相同列表上运行,而不会声明新列表。这会导致奇怪的问题。
您应该使用默认值None
并在函数开头添加一个检查:
def __init__(self, lst=None, intg=0):
if lst is None:
lst = []
有关详细信息,请参阅this post。引用帖子:
默认参数的计算结果为 功能定义时间,所以他们是 持续不断的通话。这有一些 有趣(和令人困惑)的一面 效果。一个例子:
>>> def foo(d=[]):
... d.append('a')
... return d
如果 你之前没试过这个 可能期望foo总是回归
['a']
:它应该以空的开头 列表,附加'a'并返回。 这是它实际做的:
>>> foo() ['a']
>>> foo() ['a', 'a']
>>> foo() ['a', 'a', 'a']
这是因为
d
的默认值是 当函数被分配时 创建,而不是在它被调用时。每 调用函数的时间,值 从最后一直到处闲逛 呼叫。如果你这更加怪异 把线程扔进混合中。如果两个 不同的线程正在执行 同时起作用,其中之一 他们改变了默认参数 两者都会看到变化。当然,所有这一切都是真的,如果 默认参数的值是a 可变类型。如果我们将
foo
更改为 定义为
>>> def foo2(d=0):
... d += 1
... return d
然后它将始终返回1。 (这里的区别在于
foo2
, 变量d
正在重新分配, 而在foo
中它的价值正在变化 改变。)
答案 2 :(得分:1)
问题在于默认的构造函数参数。您应该阅读此问题以找到问题的答案:“Least Astonishment” in Python: The Mutable Default Argument