我在python中编写了两个简单的代码,它们应该做同样的工作,但它并没有。 如果你能告诉我为什么会这样,并且还向我解释了“一切都是python中的一个对象”。谢谢:))
def f(p=[]):
print p
f.a += 1
print id(p)
if(f.a == 1):
p = p + [4]
else:
p = p + [5]
return p
f.a = 0
f()
f()
f()
答案:
[] 40564496 [] 40564496 [] 40564496
def f(p=[]):
print p
f.a += 1
print id(p)
if(f.a == 1):
p += [4]
else:
p +=[5]
return p
#print f()
#print f()
f.a = 0
f()
f()
f()
答案:
[] 40892176 [4] 40892176 [4, 5] 40892176
就像你看到的那样 - 第一个代码每次都有一个新的列表,第二个代码添加到最后一个使用的代码......
答案 0 :(得分:1)
你永远不应该将 mutable 对象作为python函数中的默认值传递,因为只有一个。因此,您的第二个函数始终使用相同的列表,该列表是在函数创建期间实现的。另一方面,第一个在__.response.setBody({ errorCode: err.number})
赋值期间创建新列表,因此默认arg没有变化。以这种方式编码:
p = p + [4]
def f(p=None):
if p is None:
p = []
print p
f.a += 1
print id(p)
if(f.a == 1):
p += [4]
else:
p +=[5]
return p
从来没有我的意思是“除非你真的知道你在做什么”。规则总是存在异常,但如果您需要将mutable作为默认值传递,则需要很好地理解其后果,因此您可能无法读取此答案。特别是,在许多Python样式指南中都不鼓励使用它,例如Google python style guide
不要在函数或方法定义中使用可变对象作为默认值。
这也应该导致pylint警告W0102
危险违约值(W0102): 危险默认值%s作为参数在参数的默认值中检测到可变值作为列表或字典时使用。
答案 1 :(得分:1)
运营商obj += other
和obj = obj + other
不一样。前面经常使用 inplace 修改,而后者通常会创建一个新对象。对于列表,obj += other
与obj.extend(other)
相同。
第二个重要的事情是def
语句仅针对每个范围评估一次。如果在模块范围内定义函数,则def
将被评估一次 - 包括创建其默认参数!
def foo(bar=[]):
print(id(bar))
在这种情况下,bar将始终默认为首次评估def foo
时创建的相同列表对象。
每当您修改默认值时,它将延续到下次使用此默认值时。
与此对比:
def foo(bar=None):
bar = bar if bar is not None else []
print(id(bar))
在这种情况下,每次调用函数时,默认列表都是重新创建。