简体   繁体   中英

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 this that works?

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
    # ...

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')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM