Reputation: 830
I know python treats this namespace in a different way ever since I found out about
def foo(l=[]):
l.append(1)
print(l)
foo()
foo()
foo([])
foo()
which prints the following.
[1]
[1,1]
[1]
[1,1,1]
So I was sceptical about their use as an object initializers. Then recently I encountered another similarly strange behaviour, demonstrated below.
class Foo:
bar = 0
def __init__(self):
self.a = bar
Foo()
This raises an exception as bar
is not defined inside this namespace.
class Foo:
bar = 0
def __init__(self, a=bar)
self.a = a
Foo()
Now this successfully assigns value held by a class variable foo
to an object a
inside the initializer.
Why do these things happen and how are the default argument values treated?
Upvotes: 5
Views: 171
Reputation: 363213
Three facts:
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.
Upvotes: 5