我为什么无法在Python中访问这个类成员?
我有以下代码
class Transcription(object):
WORD = 0
PHONE = 1
STATE = 2
def __init__(self):
self.transcriptions = []
def align_transcription(self,model,target=Transcription.PHONE):
pass
这里重要的是,我想把一个类里的成员当作变量的默认值。但是这样做会出现以下错误:
NameError: name 'Transcription' is not defined
为什么这样做不行呢?那有什么正确的(符合Python风格的)方法来实现类似的功能呢?
3 个回答
在你定义align_transcription这个方法的时候,Transaction类还没有被创建,但PHONE这个东西在当前的范围内是可以用的。
所以,你可以这样做:
class Transcription(object):
WORD = 0
PHONE = 1
STATE = 2
def __init__(self):
self.transcriptions = []
def align_transcription(self,model,target=PHONE):
pass
或者,如果你打算在子类或者实例中覆盖PHONE的话,可以设置一个默认值target=None:
def align_transcription(self,model,target=None):
if target is None:
target = self.PHONE
这个类在定义完成之前是和它的名字没有关联的。
我会这样写(虽然我不能保证这符合Python的风格):
class Transcription(object):
WORD = 1 # zero won't work below... need to change the value
PHONE = 2
STATE = 3
def align_transcription(self, model, target=None):
target = target or Transcription.PHONE
# or
if target is None: target = Transcription.PHONE
另外,把PHONE
设为零而不是WORD
也是可以的。这个if
语句无论常量的值是什么都能正常工作,但or
会把零值替换成PHONE
。
还有其他选择,比如在另一个类中定义常量,或者把align_transcription
方法绑定到类外:
class Transcription(object):
WORD = 0
PHONE = 1
STATE = 2
def _unbound_align_transcription(self, model, target=Transcription.PHONE):
pass
Transcription.align_transcription = _unbound_align_transcription
你无法访问它,因为在执行 def
语句时,Transcription
还没有被定义。
def align_transcription(self,model,target=PHONE):
pass
这样做就可以了。PHONE
这个名字在命名空间中是可用的,而它会在 class
语句执行完后变成 Transcription
类。
这个过程是这样的:class
是一个会被实际执行的语句。当 Python 遇到一个类的声明时,它会进入一个新的局部作用域,并执行所有在 class
语句下面缩进的内容,就像在执行一个函数一样。然后,它会把生成的命名空间、类的名字和基类的元组传给一个元类,默认情况下这个元类是 type
。元类会返回它自己的一个实例,这个实例就是实际的类。在执行 def
语句时,这些都还没有发生。
这条语句
class Foo(object):
a = 1
def foo(self):
print self.a
创建了一个命名空间 ns = {'a': 1, 'foo': foo}
,然后执行
Foo = type('Foo', (object,), ns)
这相当于
def foo(self):
print self.a
Foo = type('Foo', (object,), {'a': 1, 'foo': foo})
你可以清楚地看到,在定义 foo
时,Foo
还没有被定义,所以 Foo.a
是没有意义的。