当用@classmethod 装饰时,cls 到inc_class(cls) 的第一个参数就是类。 <class '__main__.A'> 和 <class '__main__.B'> 分别对应 A 和 B。所以cls._var 指的是A 的_var,B 也是如此。在inc_static 中,用@staticmethod 装饰没有参数,你明确指的是<class '__main__.Base'>,一个不同的_var。
注意Base 和A 的__dict__ 中的'_var': 0 属性。 @classmethod 正在做你期望它做的事情,将成员绑定到类,在本例中为 A 和 B。
>>> Base.__dict__
mappingproxy({'__module__': '__main__', '_var': 0, 'inc_class': <classmethod
object at 0x7f23037a8b38>, 'inc_static': <staticmethod object at
0x7f23037a8c18>, '__dict__': <attribute '__dict__' of 'Base' objects>,
'__weakref__': <attribute '__weakref__' of 'Base' objects>, '__doc__': None})
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None})`
拨打Base.inc_static()后:
>>> Base.__dict__
mappingproxy({'__module__': '__main__', '_var': 1, 'inc_class':
<classmethod object at 0x7f23037a8b38>, 'inc_static': <staticmethod
object at 0x7f23037a8c18>, '__dict__': <attribute '__dict__' of 'Base'
objects>, '__weakref__': <attribute '__weakref__' of 'Base' objects>,
'__doc__': None})
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None})
拨打A.inc_class()后:
>>> Base.__dict__
mappingproxy({'__module__': '__main__', '_var': 1, 'inc_class':
<classmethod object at 0x7f23037a8b38>, 'inc_static': <staticmethod
object at 0x7f23037a8c18>, '__dict__': <attribute '__dict__' of 'Base'
objects>, '__weakref__': <attribute '__weakref__' of 'Base' objects>,
'__doc__': None})
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None, '_var': 1})
有趣的是A的_var是如何初始化的。请注意,您在定义 cls._var 之前执行 cls._var += 1。正如here 所解释的,cls._var += 1 等价于cls._var = cls._var; cls._var += 1。由于way python does lookup,cls._var 的第一次读取将在A 中失败并继续在Base 中找到它。在赋值时将_var 添加到A 的__dict__ 中,值为Base._var,然后一切正常。
>>> class Base(object):
... _var = 10
... @classmethod
... def inc_class(cls):
... cls._var += 1
...
>>> class A(Base):
... pass
...
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None})
>>> A.inc_class()
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None, '_var': 11})