我已经阅读了许多关于Python中变量引用的问题,但是当我使用我不希望的代码并且它变得非常令人沮丧时,事情仍在发生。拿这段代码:
class MyClass(object) :
class_var = "original message" # same for all objects
def __init__(self, instance_var) :
self.instance_var = instance_var #particular to the object
my_object = MyClass("my instance variable")
untouched_object = MyClass("another instance_var")
# Values of class_var and instance_var as expected
MyClass.class_var = "changed message"
# attribute class_var has changed for both objects
# This changes attribute class_var for my_object only
my_object.class_var = "I am my_object"
# THIS ONLY CHANGES ATTRIBUTE CLASS_VAR FOR UNTOUCHED_OBJECT ONLY!
MyClass.class_var = "Last message"
print MyClass.class_var #prints Last Message
print my_object.class_var #prints I am my_object ???
print untouched_object.class_var #prints Last Message
这里发生了什么?当我使用类变量创建某个类的对象时,似乎object.class_attribute
最初包含指向Class.class_var
的指针,我可以通过分配给Class.class_var
来更改所有对象的属性。但是如果我明确地将object.class
属性分配给其他某个值,则指针会消失,并且更改Class.class_var
不再对该特定对象的更改产生影响,只会影响所有其他实例。这是什么意思?此外,为什么我们能够以这种方式访问和更改类属性,并且可能无法访问Python文档声称所有实例都知道的值?
答案 0 :(得分:3)
当你这样做时
my_object.class_var = "I am my_object"
您创建了一个影响类属性my_object.class_var
的实例属性MyClass.class_var
,因此对MyClass.class_var
的后续分配似乎对{{my_object
没有影响1}}。
根据其他语言的概念(例如引用和指针)尝试理解Python的数据模型可能会产生误导。尝试考虑名称,以及对象与名称的绑定。
因此,在您的示例中,MyClass.class_var
和my_object.class_var
最初都是绑定到class属性的名称,但是赋值将新的字符串对象绑定到名称my_object.class_var
。
我发现将(名称,对象)对视为字典中的(键,值)对会有所帮助。在某些情况下,这实际上是“幕后”发生的事情(例如,您自己创建的普通类),但在其他情况下(如Python的内置类型),由于效率原因,事情的实现方式略有不同。
您可能会发现这篇文章很有用:Facts and myths about Python names and values,由SO资深人士Ned Batchelder撰写。
答案 1 :(得分:2)
每个对象都有一个名为__dict__
的变量,用于存储其成员变量的值,并按名称索引。每个类还有一个名为__dict__
的变量,它存储由类名索引的类变量的值。当您使用a.v语法访问实例a的变量v时,Python首先查找a.__dict__['v']
。如果没有这样的元素,它会在类字典中查找,即a.__class__.__dict__['v']
。这就是类变量对该类的每个实例可见的方式。
但是当您分配给变量时,过程是不同的。类似a.v = 12
的语句会导致Python执行a.__dict__['v'] = 12
。它没有触及类字典。因此,正如您所期望的那样,该类的其他实例不受影响。现在,当您访问a.v时,您将获得值12,即您刚刚设置的特定于实例的值,而不是类变量的值。并且你不能再通过搞乱类变量来改变a.v,因为a
现在有自己的名为'v'的变量。
这样做的结果是你应该主要使用类变量来设置“常量”,类似于你在C中使用枚举或#define的方式。这是一个你不打算改变的值。如果将类变量限制为该使用方式,则它们非常方便且易于理解。