我通常声明在Python中的实例中使用的类变量的方式如下:
class MyClass(object):
def __init__(self):
self.a_member = 0
my_object = MyClass()
my_object.a_member # evaluates to 0
但以下也有效。这是不好的做法吗?如果是这样,为什么?
class MyClass(object):
a_member = 0
my_object = MyClass()
my_object.a_member # also evaluates to 0
第二种方法遍布Zope,但我还没有在其他任何地方看到它。那是为什么?
编辑:作为对sr2222答案的回应。我知道这两者本质上是不同的。但是,如果该类仅用于实例化对象,则两者将以相同的方式工作。那么使用类变量作为实例变量是不是很糟糕?感觉就像是,但我无法解释原因。
答案 0 :(得分:7)
问题是这是类本身还是特定对象的属性。如果整个类具有某个属性(可能有少量例外),那么无论如何都要在类上分配一个属性。如果某个奇怪的对象或子类在此属性中不同,则可以根据需要覆盖它。而且,这比为每个对象分配一个基本上恒定的属性更具内存效率;只有类的__dict__
具有该属性的单个条目,并且每个对象的__dict__
可能保持为空(至少对于该特定属性)。
简而言之,您的两个示例都是非常惯用的代码,但它们在机器级别和人类语义级别上都意味着不同的东西。
让我解释一下:
>>> class MyClass(object):
... a_member = 'a'
...
>>> o = MyClass()
>>> p = MyClass()
>>> o.a_member
'a'
>>> p.a_member
'a'
>>> o.a_member = 'b'
>>> p.a_member
'a'
在第二行,您正在设置“类属性”。这是一个名为“MyClass”的对象的属性。它存储为MyClass.__dict__['a_member'] = 'a'
。在后面的行中,您将对象属性o.a_member
设置为。这完全等同于o.__dict__['a_member'] = 'b'
。您可以看到这与p.__dict__
的单独字典无关。访问p的a_member
时,在对象字典中找不到它,并将其推迟到其类字典:MyClass.a_member
。这就是为什么修改o
的属性不会影响p
的属性,因为它不会影响MyClass
的属性。
答案 1 :(得分:4)
第一个是实例属性,第二个是class属性。它们完全不一样。实例属性附加到该类型的实际创建对象,而类变量附加到类(类型)本身。
>>> class A(object):
... cls_attr = 'a'
... def __init__(self, x):
... self.ins_attr = x
...
>>> a1 = A(1)
>>> a2 = A(2)
>>> a1.cls_attr
'a'
>>> a2.cls_attr
'a'
>>> a1.ins_attr
1
>>> a2.ins_attr
2
>>> a1.__class__.cls_attr = 'b'
>>> a2.cls_attr
'b'
>>> a1.ins_attr = 3
>>> a2.ins_attr
2
答案 2 :(得分:0)
即使您永远不会修改对象的内容,这两者也不可互换。我理解它的方式,访问类属性比访问实例属性稍慢,因为解释器本质上必须采取额外的步骤来查找类属性。
“什么是a.thing
?”
“什么是a.thing
?哦,没有实例属性thing
,我会检查它的类......”
答案 3 :(得分:0)
我有答案!我欠@mjgpy3在原帖子评论中的引用。如果分配给类变量的值是MUTABLE,则会出现差异!那么,这两个将一起改变。当新值替换旧值时,成员会分裂
>>> class MyClass(object):
... my_str = 'a'
... my_list = []
...
>>> a1, a2 = MyClass(), MyClass()
>>> a1.my_str # This is the CLASS variable.
'a'
>>> a2.my_str # This is the exact same class variable.
'a'
>>> a1.my_str = 'b' # This is a completely new instance variable. Strings are not mutable.
>>> a2.my_str # This is still the old, unchanged class variable.
'a'
>>> a1.my_list.append('w') # We're changing the mutable class variable, but not reassigning it.
>>> a2.my_list # This is the same old class variable, but with a new value.
['w']
编辑:这几乎是bukzor写的。他们得到了最好的答案标记。