为什么这两个代码之间存在差异?

时间:2016-06-28 21:28:33

标签: python

我在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

就像你看到的那样 - 第一个代码每次都有一个新的列表,第二个代码添加到最后一个使用的代码......

2 个答案:

答案 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 += otherobj = obj + other不一样。前面经常使用 inplace 修改,而后者通常会创建一个新对象。对于列表,obj += otherobj.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))

在这种情况下,每次调用函数时,默认列表都是重新创建