为什么两个不同的对象包含相同的列表?

时间:2015-05-04 09:06:03

标签: python object

我刚刚解决了一个我不明白的奇怪问题:

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]

为什么两个不同的对象包含相同的列表?

4 个答案:

答案 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对象。 *

*该语言允许实现在知道值是不可变的时重用同一个对象。在实践中,主要的现有实现对小整数执行此操作,特殊单例常量5TrueFalse,可能还有一些字符串。使用(默认配置的)CPython时,None555不被视为小整数,但666是。

答案 1 :(得分:0)

它们不是两个不同的对象。实际上它们是单个对象,b和b2对象指向同一个列表对象,如果你编辑b的列表,则列表是可变的,因为b2引用了相同的列表

enter image description here

答案 2 :(得分:0)

这是因为InputScope是类属性,它对所有a_list实例都是全局的。如果您希望B类的不同实例具有自己的列表,您应该在B中定义如下:

__init__

答案 3 :(得分:0)

实际上,这两个对象甚至不包含列表。当您创建班级B时,您将a_list放入其中。当您访问b.a_list时,解释程序会发现b没有a_list(您可以通过检查b.__dict__来验证这一点)并深入了解课程。查看b2时,完全相同的流程会找到相同的列表。

MarcTudurí的回答显示了如何在每个新的B实例中创建单独的列表。