这两个类定义的结构相同,除了在奇怪的()类定义中,属性'd'是一个列表,而在normal()类定义中它是一个int。我不明白为什么奇怪的()类导致self.d = d,而类normal()不是这种情况。为什么Python会在这种情况下处理int和列表?
class weird:
def __init__(self):
d = [1,2,3]
self.d = d
for x in range(3):
d[x] = 10+x
print "d =", d
print "self.d =", self.d
class normal:
def __init__(self):
d = 1
self.d = d
d = 11
print "d =", d
print "self.d =", self.d
当我运行代码时,我得到了
>>> a=weird()
d = [10, 11, 12]
self.d = [10, 11, 12]
>>> b=normal()
d = 11
self.d = 1
答案 0 :(得分:7)
你正在混淆对象的变异。
在一种方法中,您为d
分配了新值,更改了指向的内容:
d = 11
但在另一种方法中,您更改了d
中包含的值:
d[x] = 10 + x
注意那里的[x]
;从本质上讲,你是在告诉python这样做:
d.__setitem__(x, 10 + x)
指向列表的变量d
的值永远不会更改。 d
引用的列表中的值确实会发生变化。
看看我之前的这个答案,它更详细地说明了这两个陈述之间的区别:Python list doesn't reflect variable change。
答案 1 :(得分:2)
事实上,这里的语言完全一致。您正在观察两种不同的行为,因为您正在执行两种根本不同的操作。
__init__
的前两行在两个类中都是一致的(d
的不同类型除外):
class WeirdOrNormal:
def __init__(self):
d = ... # 1 or [1, 2, 3]
self.d = d
此时,d
和self.d
都指向同一个对象。
然而,在那之后,两个班级分歧:
weird
通过引用修改对象:
for x in range(3):
d[x] = 10+x
由于d
和self.d
都指向同一个对象,因此可以通过两者来观察更改。
normal
重新绑定d
指向self.d
以外的其他地方:
d = 11
通过这样做,您已经打破了d
和self.d
之间的链接。他们现在完全独立。
如果您要更改weird
以重新引用引用,就像normal
那样,您会看到这两个类的行为一致:
class notweird:
def __init__(self):
d = [1,2,3]
self.d = d
d = [10+x for x in self.d]
print "d =", d
print "self.d =", self.d
a = notweird()
打印
d = [11, 12, 13]
self.d = [1, 2, 3]
答案 2 :(得分:1)
对于文档:
值可以改变的对象被认为是可变的;对象的 一旦创建它们,值就不可更改,称为不可变。 (该 包含对a的引用的不可变容器对象的值 当后者的值改变时,可变对象可以改变;然而 容器仍然被认为是不可变的,因为收集了 它包含的对象无法更改。所以,不变性不是 与具有不可改变的值严格相同,它更加微妙。) 对象的可变性由其类型决定;例如, 数字,字符串和元组是不可变的,而词典和 列表是可变的。
在您的情况下list
是可变的,int
是不可变的。没什么奇怪的。
有关Data model的更多信息。
答案 3 :(得分:0)
在第一个示例中,d
和self.d
都指向可变对象。向对象中的元素添加10时,您正在修改该可变对象。由于d
和self.d
都指向该对象,因此它们都“看到”了结果。
在第二个示例中,您将重新分配d以指向不同的不可变数字,因此d
和self.d
指向两个不同的事物。
注意区别:在一种情况下,它们都指向您正在更改的相同值,而在另一种情况下,它们指向两个不同的值。