这是有问题的代码的简化版本:
class thing:
def __init__(self, data1, data2={'foo': 1}):
self.data2 = data2
self.data2['bar'] = data1
datas = ['FIRST', 'SECOND']
things = [thing(x) for x in datas]
for p in things:
print p.data2['bar']
我希望此代码返回:
FIRST
SECOND
但是,它实际上返回:
SECOND
SECOND
为什么?
我最好的猜测是:
ur_dict = {'foo': 1}
,thing
我不是在创建新的字典self.data2={'foo': 1}
,而是在初始化对的引用ur_dict
,bar: data1
到时self.data2
,实际上是在将键值对ur_dict
自身添加。这将更新data2
列表中每个单个对象的字段。我通过将以下代码段附加到上面的代码中来测试了这个假设:
things[0].data2['bar'] = 'FIRST'
for p in things:
print p.data2['bar']
果然,结果是:
FIRST
FIRST
所以我认为我的假设可能是正确的,但对我来说仍然是个谜。我的问题似乎与这个问题非常相关-当我在构造函数中创建默认值时,该值是类变量而不是实例变量吗?python为什么不为对象中参数的默认值创建新对象?有没有一种好的方法可以在将来概念化或捕获这种错误?有什么好的参考资料可了解此处的情况?
(如果我弄乱了行话,请提前道歉;我是接受正规教育的数学家。)
编辑:@CrazyPython[::-1]
提到这是函数的属性,而不是类或对象。我创建了一个带有可变默认参数的函数示例,我试图找出如何以上面对对象和类的体验来破坏它。想到了这个:
EXPONENT = 1
def fooBar(x, y=EXPONENT):
return x**y
print EXPONENT
print foo(5)
EXPONENT = 2
print EXPONENT
print foo(5)
但是,它返回:
1
5
2
5
什么是“破坏”这一点的好方法,以说明为什么不在此处使用可变的默认参数?
self.data2={'foo': 1}
是一个可变的默认参数。绝对不要那样做。99%的时间是错误的。
def foo(a, b={}):
...
不等于
def foo(a, b=None):
if b is None:
b = {}
b
不是每次都重建。这是同一个对象。
有没有一种好的方法可以在将来概念化或捕获这种错误?
使用PyCharm或其他好的编辑器
当我在构造函数中创建默认值时,此值是类变量而不是实例变量吗?
不,不,不,不,不。它与函数绑定,而不与类或实例绑定。这是行为适用于所有功能。它与课程或链接的问题无关。
python为什么不为对象中参数的默认值创建新对象?
性能和兼容性。构造对象是一项潜在的昂贵操作。
您不是继承自object
。那很糟。*
为什么此python代码会更改列表中每个对象的字段?
没有上下文,那是一个不好的称呼。它询问代码。当我们阅读标题时,我们没有代码。
声明函数时,将评估默认参数。(不是在执行时,而是在声明时)它们与函数绑定在一起。执行函数时,不会生成默认参数的副本。您可以直接修改默认参数。调用的下一个函数将接收相同的对象,并进行修改。
*您似乎是一名教授等。请不要因迷因而得罪。那只是从互联网上获得建议的风险。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句