我知道我们可以使用self
或class
名称访问类属性。
但是我有些困惑,为什么下面的方法同样有用
class Crazy(object):
VERSION = 1
def __init__(self, version=VERSION):
print version
但这不是
class Crazy(object):
VERSION = 1
def __init__(self):
print VERSION
答案 0 :(得分:3)
一个类定义,即class ...:
中的块,像任何常规Python代码块一样被求值。在class
块的末尾,在该块内定义的每个本地名称都成为类的__dict__
的一部分。 class
语法或多或少只是语法糖:
Crazy = type('Crazy', (object,), {'VERSION': 1, ...})
请参见https://docs.python.org/3/library/functions.html#type。
鉴于此,您希望它能正常工作,对吧?
VERSION = 1
def foo(bar=VERSION):
print(bar)
(有关其行为的更多解释,请参见this。)
在class
块中,此方法的工作方式完全相同,唯一的特殊行为是您不会创建 global 名称,但会创建类的名称{{1 }}。
文档中的相关段落在这里:
然后使用新创建的本地名称空间和原始的全局名称空间在新的执行框架(请参见Naming and binding)中执行类的套件。 (通常,套件主要包含函数定义。)当类的套件完成执行时,其执行框架将被丢弃,但其本地名称空间将被保存。然后,使用基类的继承列表和属性字典的已保存本地名称空间创建类对象。类名称绑定到原始本地名称空间中的该类对象。
https://docs.python.org/3/reference/compound_stmts.html#class-definitions
尽管在定义了类之后,该隐式命名空间不再存在,所以它不起作用:
__dict__
作用域规则遵循常规查找链:
这些都不是正确的,因为此时def __init__(self):
print(VERSION)
只是VERSION
的一个属性,因此只能以Crazy
或Crazy.VERSION
的形式访问,后者实际上实际上也不存在,而是退回到它自己的查找链上并遍历到self.VERSION
。