<p>这不是一个声明,这是一个任务。。。类中的变量,而不是实例中的变量。在</p>
<p>考虑以下输出:</p>
<pre><code>>>> 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'}
</code></pre>
<p>这里<code>x</code>是类K1的一个实例,有一个名为<code>attr</code>的属性,<code>y</code>是类K2的实例,有一个不同的属性<code>another</code>。但是:</p>
^{pr2}$
<p>那是从哪里来的?它来自课堂:</p>
^{3}$
<p>这有点乱,但是你可以看到<code>attr</code>坐在那里。如果你看<code>x.__class__.__dict__</code>没有{<cd2>}:</p>
<pre><code>>>> 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>})
</code></pre>
<p>当您获得实例的属性时,比如<code>x.attr</code>或<code>y.attr</code>,Python首先查找附加到实例本身的东西。如果什么也没找到,它会“向上看”看是否有其他东西定义了这个属性。对于具有继承的类,这涉及到遍历“成员解析顺序”列表。在本例中,不需要担心继承,但下一步是查看类本身。这里,在K2中,类中有一个名为<code>attr</code>的属性,这就是y.attr生成的。在</p>
<p>您可以更改class属性以更改<code>y.attr</code>中显示的内容:</p>
<pre><code>>>> K2.attr = 'newvalue'
>>> y.attr
'newvalue'
</code></pre>
<p>实际上,如果您创建K2()的另一个实例,它也会获取新值:</p>
<pre><code>>>> z = K2()
>>> z.attr
'newvalue'
</code></pre>
<p>请注意,更改x的<code>attr</code>不会影响K1()的新实例:</p>
<pre><code>>>> w = K1()
>>> w.attr = 'private to w'
>>> w.attr
'private to w'
>>> x.attr
'value'
</code></pre>
<p>这是因为<code>w.attr</code>实际上是<code>w.__dict__['attr']</code>,而{<cd8>}实际上是{<cd16>}。另一方面,<code>y.attr</code>和{<cd18>}实际上都是<code>y.__class__.__dict__['attr']</code>和{<cd20>},由于<code>y.__class__</code>和{<cd22>}都是{<cd23>},因此<code>K2.attr</code>同时改变。在</p>
<p>(不过,我不确定写原始问题中提到的那一页的人是否意识到了这一切。创建一个类级别的属性,然后创建一个具有相同名称的实例级属性,这有点毫无意义。)</p>