在Python中声明类变量的两种方法中的最佳方法

时间:2012-08-20 02:58:29

标签: python class

我通常声明在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答案的回应。我知道这两者本质上是不同的。但是,如果该类仅用于实例化对象,则两者将以相同的方式工作。那么使用类变量作为实例变量是不是很糟糕?感觉就像是,但我无法解释原因。

4 个答案:

答案 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写的。他们得到了最好的答案标记。