Why can I not access this class member in python?
I have the following code
class Transcription(object):
WORD = 0
PHONE = 1
STATE = 2
def __init__(self):
self.transcriptions = []
def align_transcription(self,model,target=Transcription.PHONE):
pass
The important part here is that I would like to have a class member as default value for a variable. This however gives the following error:
NameEr开发者_如何学JAVAror: name 'Transcription' is not defined
Why is this not possible and what is the right (pythonic) way to do something like this.
You can't access it because Transcription
isn't defined at the time that the def
statement is running.
def align_transcription(self,model,target=PHONE):
pass
will do the trick. The PHONE
name is available in the namespace which will become the Transcription
class after the class
statement finishes executing.
The way this works is that class
is a statement that actually gets run. When Python encounters a class statement, it enters a new local scope and executes everything that's indented under the class
statement as if it were a function. It then passes the resulting namespace, the name of the class and a tuple of the baseclasses to the metaclass which is type
by default. The metaclass returns an instance of itself which is the actual class. None of this has occurred when the def
statement executes.
The statement
class Foo(object):
a = 1
def foo(self):
print self.a
creates a namespace ns = {'a': 1, 'foo': foo}
and then executes
Foo = type('Foo', (object,), ns)
This is equivalent to
def foo(self):
print self.a
Foo = type('Foo', (object,), {'a': 1, 'foo': foo})
You can clearly see that Foo
is not defined at the time that foo
is being defined so Foo.a
makes no sense.
The class is not associated with its name until the end of the definition.
The way I would write this (and I can't guarantee that it's Pythonic) is:
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
Alternatively, setting PHONE
to zero instead of WORD
will be fine. The if
statement will work regardless of the values of the constants, but the or
will replace a zero value with PHONE
.
Other options are to define the constants in another class or to bind the align_transcription
method outside of the class:
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
The Transaction class does not exist yet when you define the align_transcription method, but PHONE is available in the scope. So, you can do either this way:
class Transcription(object):
WORD = 0
PHONE = 1
STATE = 2
def __init__(self):
self.transcriptions = []
def align_transcription(self,model,target=PHONE):
pass
or with a target=None default if you plan to override PHONE in subclasses or instances:
def align_transcription(self,model,target=None):
if target is None:
target = self.PHONE
精彩评论