我刚刚解决了一个我不明白的奇怪问题:
class A:
a_number = 666
a = A()
a2= A()
a.a_number = 555
print a2.a_number # => 666
这种情况对我来说是完全清楚的。但是看看下一个例子:
class B:
a_list = [1,2]
b = B()
b2 = B()
b.a_list[1] = 666
print b2.a_list # => [1,666]
为什么两个不同的对象包含相同的列表?
答案 0 :(得分:1)
正如所有其他答案所指出的那样,a_list
是一个类属性,在所有实例之间共享。
但a_number
也是一个类属性,在所有实例之间共享。那么,为什么会有所不同?
因此:
a.a_number = 555
该分配在a_number
实例中创建实例属性a
,隐藏了class属性。如果你对列表做了同样的事情,你会得到同样的效果:
>>> b.a_list = [1,2,3]
>>> b2.a_list
[1,2]
但那不是你做的。相反,你变异列表:
b.a_list[1] = 666
这是b.a_list[1]
的作业,但不是b.a_list
的作业。因此,它不会在b
对象中创建实例属性。
如果您可以就地a.a_number
进行变异,它也会显示在a2.a_number
中。由于数字不可变,因此无法直接看到数字。但你可以通过比较a.a_number is a2.a_number
或查看他们的id
来间接地看到间接 - 虽然这不是一个完美的测试,因为a.a_number, a2.a_number = 5, 5
,甚至{ {1}},仍然可以为您提供相同的对象,不是因为它们仍然使用class属性,而是因为它们现在都有自己的实例属性,它们都引用相同的数字a.a_number, a2.a_number = 2+3, 6-1
对象。 *
*该语言允许实现在知道值是不可变的时重用同一个对象。在实践中,主要的现有实现对小整数执行此操作,特殊单例常量5
,True
和False
,可能还有一些字符串。使用(默认配置的)CPython时,None
和555
不被视为小整数,但666
是。
答案 1 :(得分:0)
它们不是两个不同的对象。实际上它们是单个对象,b和b2对象指向同一个列表对象,如果你编辑b的列表,则列表是可变的,因为b2引用了相同的列表
答案 2 :(得分:0)
这是因为InputScope
是类属性,它对所有a_list
实例都是全局的。如果您希望B
类的不同实例具有自己的列表,您应该在B
中定义如下:
__init__
答案 3 :(得分:0)
实际上,这两个对象甚至不包含列表。当您创建班级B
时,您将a_list
放入其中。当您访问b.a_list
时,解释程序会发现b
没有a_list
(您可以通过检查b.__dict__
来验证这一点)并深入了解课程。查看b2
时,完全相同的流程会找到相同的列表。
MarcTudurí的回答显示了如何在每个新的B实例中创建单独的列表。