views:

49

answers:

1

I am writing a new class in Python (2.5). My immediate goal is to:

GOAL: Use the value of a class (static) attribute as the default value for an instance attribute

I can add logic to the __init__ method to do this, and it works fine.

In an effort to tidy up the body of the __init__ method, however, I tried to set a default value for one of its arguments, instead of deriving the default inside the method, itself. This construct raises a NameError exception, though, and I don't understand why.

Consider the two occurrences of the variable MyClass.__DefaultName in following (admittedly nonsensical) example:

class MyClass():

    __DefaultName = 'DefaultName'


    def __init__(
            SELF
            ,name = MyClass.__DefaultName # <-- FAILS
    ):

            if name: SELF.__Name = name
            else: SELF.__Name = MyClass.__DefaultName # <-- SUCCEEDS

As the annotations suggest, I can reference MyClass.__DefaultName within the body of the __init__ method, but I get a NameError exception when I try to use that same reference as an argument default.

I've tried myriad variations on the syntax, and have read copious doc/PEPs in an effort to learn why the interpreter handles these two references differently. I'm sure I've encountered the answer somewhere along the way, but I just haven't recognized it yet.

I would greatly appreciate it if someone could help me understand why the example above produces a NameError exception - and, ideally, which syntax (if any) would avoid the exception. Thank you, in advance.

(P.S. I have an actual business case for wanting to do this. I can provide details; I just didn't want to obscure the original post with extraneous information.)

+2  A: 

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 __DefaultName yet. To work around that, you can pass a special unique value to __init__(), such as None:

def __init__(self, name=None):
    if name is None:
        name = MyClass.__DefaultName
    .
    .
    .
Frédéric Hamidi
Firstly, thank you for the answer. That makes perfect sense. Ironically, I spent most of today learning about decorators - and stopped reading right before this paragraph in the doc. Secondly, I almost fell off my chair when I read your response, because it presages doom for many of my classes where I've used variables as default values. There's no syntax error, but the definitely won't do what I want them to do. THANK YOU immensely for clarifying this important point for me. Good day.
manniongeo
Be careful about mutable default values (I think that's already cited in the documentation). If you have something like `def func(mylist=[])`, then ONE instance of the list will be used across ALL function calls, which is certainly not what you want. http://effbot.org/zone/default-values.htm
Denilson Sá