python3 可变属性是共享的吗?

Leo*_*Leo 3 python mutable python-3.x

在代码中我实例化了同一类的两个不同对象,怎么可能object1改变object2的属性?如何保留不同的“self.mutable”变量?我的错误在哪里?:-)

谢谢

class Class:
    mutable = {}
    immutable = 0

    def change(self):
        self.immutable = 1
        self.mutable["key"] = "value"

    def observe(self):
        print(self.immutable, self.mutable)


object1, object2 = Class(), Class()

object1.change()
object2.observe()
# output is: 0 {'key': 'value'}
Run Code Online (Sandbox Code Playgroud)

tim*_*geb 5

您已经在类级别定义了mutable和,因此两者将在 的所有实例之间共享。链接问题中的答案详细解释了如何避免您正在观察到的共享行为,因此我将仅解释您的代码发生的情况。immutableClass

原则上,这种共享与属性的可变或不可变无关,但代码中存在一些细微差别,可能会使其变得混乱。

在 的情况下mutable,观察到的行为很容易解释。

首先,字典mutable在内存中始终是同一个对象:

>>> o1, o2 = Class(), Class()                                                                         
>>> o1.mutable is o2.mutable is Class.mutable                                                         
True
Run Code Online (Sandbox Code Playgroud)

当你mutable以任何方式发生变异时,在任何引用该字典的地方都会看到这种变化。

>>> Class.mutable                                                                                     
{}
>>> o2.mutable[1] = 2                                                                                 
>>> o1.change()                                                                                       
>>> Class.mutable                                                                                     
{1: 2, 'key': 'value'}
Run Code Online (Sandbox Code Playgroud)

到目前为止,这一切都是预料之中的。棘手的部分immutable是,您不会Class.immutable在更改中发生变异,而是将属性分配给正在调用的immutable实例(self) !change

在调用更改之前,仅存在于类级别,并且在实例或immutable上查找时通过类访问。(注意和的实例字典是如何为空的。)o1o2o1o2

>>> o1, o2 = Class(), Class()                                                                         
>>> o1.immutable, o2.immutable, Class.immutable                                                       
(0, 0, 0)
>>> o1.__dict__, o2.__dict__, 'immutable' in Class.__dict__                                           
({}, {}, True)
Run Code Online (Sandbox Code Playgroud)

change调用时,您只需在实例上o2设置属性!immutable = 1o2

>>> o2.change()                                                                                       
>>> o1.immutable, o2.immutable, Class.immutable                                                       
(0, 1, 0)
>>> o1.__dict__, o2.__dict__, 'immutable' in Class.__dict__                                           
({}, {'immutable': 1}, True)
>>> o1.immutable is Class.immutable                                                                   
True
>>> o2.immutable is Class.immutable                                                                   
False
Run Code Online (Sandbox Code Playgroud)

重要的是要理解在类级别设置的可变和不可变对象以完全相同的方式共享。唯一的区别是可变对象没有可以更改它们的方法。但是,如果您已经完成self.mutable = {'key': 'value'}change调用change特定实例,则mutable通过点表示法在实例上查找时,在实例上定义的属性将优先于在类级别定义的属性。