Three facts:
- The name (left side) of a default argument is a local variable name inside the function body.
- The value (right side) of a default argument is evaluated in the scope where the function is defined, at the time of function definition.
- Code within a class block is executed in a temporary namespace during class definition. The class block is not treated like an enclosing scope, which may be surprising if you were expecting behavior similar to a nested
def.
Point 3 is the most subtle and perhaps contrary to initial expectations. It's documented in the execution model (section 4.2.2. Resolution of names):
The scope of names defined in a class block is limited to the class block; it does not extend to the code blocks of methods
This is why the name bar is not resolved in your second example:
class Foo:
bar = 0
def __init__(self):
self.a = bar # name "bar" isn't accessible here, but code is valid syntax
Foo() # NameError: name 'bar' is not defined
Note that bar value, 0, would still be accessible from within the method as a class attribute: via either Foo.bar or self.bar.
You should now understand why the final example does work:
class Foo:
bar = 0
def __init__(self, a=bar):
self.a = a
Foo()
And, considering points 1-3 above, you should also be able to correctly predict what happens here:
class Foo:
def __init__(self, a=bar):
self.a = a
bar = 0
Foo()
There's more information about the weird class scope over in UnboundLocalError: local variable referenced before assignment why LEGB Rule not applied in this case.