关于Python类和实例变量的混淆

3
我看到了以下Python文档,其中写道“在类中定义变量”将是类变量:

程序员注意:在类定义中定义的变量是类变量;它们由所有实例共享。”

但是当我编写以下示例代码时:

class CustomizedMethods(object):
    class_var1 = 'foo'
    class_var2 = 'bar'

cm1 = CustomizedMethods()
cm2 = CustomizedMethods()
print cm1.class_var1, cm1.class_var2 #'foo bar'
print cm2.class_var1, cm2.class_var2 #'foo bar'
cm2.class_var1, cm2.class_var2 = 'bar','for'
print cm1.class_var1, cm1.class_var2 #'foo bar' #here not changed as my expectation
print cm2.class_var1, cm2.class_var2 #'bar foo' #here has changed but they seemed to become instance variables.

我感到困惑,因为我尝试的方法与Python官方文档不同。

5个回答

4
当您在实例上分配属性时,即使它先前存在于类上,也会分配给实例。一开始,class_var1和class_var2确实是类属性。但是当您执行cm1.class_var1 =“bar”时,您并没有更改此类属性。相反,您正在创建一个新属性,也称为class_var1,但这个属性是实例cm1上的实例属性。
以下是另一个示例,展示了不同之处,尽管仍然可能有点难以理解:
>>> class A(object):
...     var = []
>>> a = A()
>>> a.var is A.var
True
>>> a.var = []
>>> a.var is A.var
False

一开始,a.var is A.var 是正确的(即它们是同一个对象):因为 a 没有自己的叫做 var 的属性,试图访问该属性会通过类去访问。当你给a赋予它自己的实例属性后,它就不再与类上的那个属性相同了。


谢谢!这解决了我的困惑。你有什么想法为什么在Python中会出现这种混乱的情况? - user854270
@Gasso:不确定你的意思。没有什么是“搞砸了”的。这是Python的定义和正常行为。 - BrenBarn
我说它很混乱,因为这不是开发人员所期望的行为,它很令人困惑。变量“first”的行为就像静态类变量,然后又像类成员。对于这些有限定词,如果Python使用它们而不是将“cm1.class_var1”从静态切换到动态,那么会更容易些。 - user854270

1

你正在实例上分配属性,因此它们在那一点上变成实例变量。Python会在您指定的任何对象上查找属性,然后如果它在那里找不到它们,就会查找继承链(到类、类的父级等)。因此,您在实例上分配的属性“遮盖”或“隐藏”了同名的类属性。


0

当您重新分配cm2变量时,您创建了新的实例变量,这些变量“隐藏”了类变量。

>>> CustomizedMethods.class_var1 = 'one'
>>> CustomizedMethods.class_var2 = 'two'
>>> print cm1.class_var1, cm1.class_var2
one two
>>> print cm2.class_var1, cm2.class_var2
bar for

0

尝试

print cm1.__dict__ 
print cm2.__dict__ 

它将是启发性的...

当您向 cm2 请求属性时,它首先在实例的属性中查找(如果有一个匹配名称),然后如果没有匹配的属性在类属性中查找。

因此,class_var1 和 class_var2 是类属性的名称。

还可以尝试以下内容:

cm2.__class__.class_var1 = "bar_foo" 
print cm1.class_var1 

你期望什么?

0

字符串是不可变的,所以类和实例变量之间的区别并不明显。对于类定义中的不可变变量,主要要注意的是内存使用较少(即,如果您有1000个CustomizedMethods的实例,仍然只有一个字符串"foo"存储在内存中)。

然而,如果不知道自己在做什么,使用类中的可变变量可能会引入微妙的错误。

考虑以下情况:

class CustomizedMethods(object):
    class_var = {}

cm1 = CustomizedMethods()
cm2 = CustomizedMethods()

cm1.class_var['test'] = 'foo'
print cm2.class_var
  'foo'

cm2.class_var['test'] = 'bar'
print cm1.class_var
   'bar'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接