Can I use a class attribute as a default value for an instance method?
I would like to use a class attribute as a default value for one of the arguments to my class's __init__
method. This construct raises a NameError
exception, though, and I don't understand why:
class MyClass():
__DefaultName = 'DefaultName'
def __init__(self, name = MyClass.__DefaultName):
self.name = name
Why does this fail, and is there a way to do t开发者_如何学运维his that works?
An important thing to keep in mind with Python is when different bits of code are executed, along with the fact that class
and def
statements are executed when seen, not just stored away for later. With a def
it's a little easier to understand because the only thing being executed is whatever is between the ()
s -- so in your code above
def __init__( SELF, name = MyClass.__DefaultName ):
when Python sees MyClass.__DefaultName
it tries to find it first in the local
namespace, then the module (aka global
) namespace, and finally in builtins
.
What is the local
namespace when executing a class
statement? That's the fun part -- it is what will become the class
namespace, but at the moment it is anonymous -- so you can't reference it by name (aka MyClass
in your code) but you can directly reference anything that has already been defined... and what has been defined? In your class example only one thing -- __DefaultName
. So your __init__
should look like this:
def __init__( SELF, name=__DefaultName ):
Keep in mind that you can't change MyClass._MyClass__DefaultName
later and have those changes show up in new instances. Why? Because the __init__
def is executed only once, and whatever value __DefaultName
had at that moment has been stored away and will always be used -- unless you directly specify a new value when you create a new instance:
my_instance = MyClass(name='new name')
That's because, according to the documentation:
Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined
When __init__()
is defined, the definition of MyClass
is incomplete, as it's still being parsed, so you can't refer to MyClass.__DefaultName
yet. One way to work around that is to pass a special unique value to __init__()
, such as None
:
def __init__(self, name=None):
if name is None:
name = MyClass.__DefaultName
# ...
精彩评论