这不是声明,而是对类内变量的赋值...,而不是实例内的变量。
考虑以下输出:
>>> class K1(object):
... def __init__(self):
... self.attr = 'value'
...
>>> x = K1()
>>> x.__dict__
{'attr': 'value'}
>>> class K2(object):
... attr = 'value'
... def __init__(self):
... self.another = 'value2'
...
>>> y = K2()
>>> y.__dict__
{'another': 'value2'}
这x
是类 K1 的一个实例,具有一个名为 的属性attr
,并且y
是一个类 K2 的实例,具有一个名为 的不同属性another
。但:
>>> y.attr
'value'
那个是从哪里来的?它来自课堂:
>>> y.__class__.__dict__
dict_proxy({'__module__': '__main__', 'attr': 'value',
'__dict__': <attribute '__dict__' of 'K2' objects>,
'__weakref__': <attribute '__weakref__' of 'K2' objects>,
'__doc__': None, '__init__': <function __init__ at 0x80185b9b0>})
这有点乱,但你可以看到attr
坐在那儿。如果你看x.__class__.__dict__
没有attr
:
>>> x.__class__.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'K1' objects>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'K1' objects>,
'__doc__': None, '__init__': <function __init__ at 0x80185b938>})
当您获得实例的属性时,例如x.attr
or y.attr
,Python 首先查找附加到实例本身的内容。但是,如果没有找到任何东西,它会“向上查找”以查看是否有其他东西定义了该属性。对于具有继承的类,这涉及通过“成员解析顺序”列表。在这种情况下,无需担心继承,但下一步是查看类本身。在这里,在 K2 中,类中有一个名为 的属性,attr
这就是 y.attr 产生的。
您可以更改类属性以更改显示的内容y.attr
:
>>> K2.attr = 'newvalue'
>>> y.attr
'newvalue'
事实上,如果你创建另一个 K2() 实例,它也会获取新值:
>>> z = K2()
>>> z.attr
'newvalue'
请注意,更改 xattr
不会影响 K1() 的新实例:
>>> w = K1()
>>> w.attr = 'private to w'
>>> w.attr
'private to w'
>>> x.attr
'value'
那是因为w.attr
是真的w.__dict__['attr']
,而且x.attr
是真的x.__dict__['attr']
。另一方面,y.attr
and z.attr
are both really y.__class__.__dict__['attr']
and z.__class__.__dict__['attr']
,并且因为y.__class__
and z.__class__
are both K2
,都在改变K2.attr
变化。
(不过,我不确定编写原始问题中引用的页面的人是否意识到这一切。创建一个类级属性,然后创建一个具有相同名称的实例级属性是毫无意义的。)