Python中定义类变量的正确方式

349

我注意到在Python中,人们有两种不同的方式来初始化他们的类属性。

第一种方式如下:

class MyClass:
  __element1 = 123
  __element2 = "this is Africa"

  def __init__(self):
    #pass or something else

另一种样式看起来像:

class MyClass:
  def __init__(self):
    self.__element1 = 123
    self.__element2 = "this is Africa"

正确初始化类属性的方式是什么?


8
使用字符串差异不大,但如果使用由引用存储的字典或列表,则会得到完全不同的结果。 - Bastian
2个回答

737

两种方式都不一定正确或错误,它们只是两种不同类型的类元素:

  • __init__ 方法之外的元素是静态元素,属于该类。
  • __init__ 方法内的元素是对象 (self) 的元素,不属于该类。

通过一些代码,您会更清楚地看到:

class MyClass:
    static_elem = 123

    def __init__(self):
        self.object_elem = 456

c1 = MyClass()
c2 = MyClass()

# Initial values of both elements
>>> print c1.static_elem, c1.object_elem 
123 456
>>> print c2.static_elem, c2.object_elem
123 456

# Nothing new so far ...

# Let's try changing the static element
MyClass.static_elem = 999

>>> print c1.static_elem, c1.object_elem
999 456
>>> print c2.static_elem, c2.object_elem
999 456

# Now, let's try changing the object element
c1.object_elem = 888

>>> print c1.static_elem, c1.object_elem
999 888
>>> print c2.static_elem, c2.object_elem
999 456

正如您所看到的,当我们更改了类元素时,两个对象都发生了变化。但是,当我们更改了对象元素时,另一个对象保持不变。


2
但是由于__init__总是在对象创建后执行,因此它实际上等同于在__init__之外定义变量,对吗? - jeanc
3
如果您更改类属性(在__init __()之外定义的属性),它将影响整个类。这也会影响其他实例,而实例属性(在__init __()中定义)是针对每个实例特定的。 - nitsas
102
不完全准确:当通过类(MyClass.static_element = X)进行分配时,static_elm会为所有类实例更改,如所示。但是,如果通过类实例进行分配,则对于该实例,static_elm将成为实例成员。如果执行:c1.static_elem = 666,则print c1.static_elem, c2.static_elem将产生666, 999。从类内部,self.static_elm返回MyClass.static_elm,直到被分配为止self.static_elm = X。然后,会创建一个新的self.static_elm,遮蔽了类变量(仍可通过MyClass.static_elm访问)。 - Lobotomik
3
Lobotomik做了清晰的解释。是的,Python上的这个设计很奇怪,这很容易让人混淆,因为类元素可能会突然变成实例元素。 - Clock ZHONG
8
@Lobotomik:我认为它只是“shadowing”类变量,因为您仍然可以通过c1.class.static_elem访问未修改的类变量。您所说的“static_elm将成为实例成员”的话,我理解为static_elem将从类变量更改为实例变量。但事实并非如此。 - gebbissimo
显示剩余9条评论

22

我认为这个示例解释了风格之间的区别:

james@bodacious-wired:~$cat test.py 
#!/usr/bin/env python

class MyClass:
    element1 = "Hello"

    def __init__(self):
        self.element2 = "World"

obj = MyClass()

print dir(MyClass)
print "--"
print dir(obj)
print "--"
print obj.element1 
print obj.element2
print MyClass.element1 + " " + MyClass.element2
james@bodacious-wired:~$./test.py 
['__doc__', '__init__', '__module__', 'element1']
--
['__doc__', '__init__', '__module__', 'element1', 'element2']
--
Hello
World
Traceback (most recent call last):
  File "./test.py", line 17, in <module>
    print MyClass.element2
AttributeError: class MyClass has no attribute 'element2'

element1绑定到类,element2绑定到类的实例。


我无法编辑或建议编辑。obj.element1obj.element2的输出混乱了。 - Git Gud

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