Weird scoping behavior in python Weird scoping behavior in python python-3.x python-3.x

Weird scoping behavior in python


Class block scope is special. It is documented here:

A class definition is an executable statement that may use and definenames. These references follow the normal rules for name resolutionwith an exception that unbound local variables are looked up in theglobal namespace. The namespace of the class definition becomes theattribute dictionary of the class. The scope of names defined in aclass block is limited to the class block; it does not extend to thecode blocks of methods – this includes comprehensions and generatorexpressions since they are implemented using a function scope.

Basically, class blocks do not "participate" in creating/using enclosing scopes.

So, it is actually the first example that isn't working as documented. I think this is an actual bug.

EDIT:

OK, so actually, here's some more relevant documentation from the data model, I think it all is actually consistent with the documentation:

The class body is executed (approximately) as exec(body, globals(),namespace). The key difference from a normal call to exec() is thatlexical scoping allows the class body (including any methods) toreference names from the current and outer scopes when the classdefinition occurs inside a function.

So class blocks do participate in using enclosing scopes, but for free variables (as is normal anyway). In the first piece of documentation that I'm quoting, the part about "unbound local variables are looked up in the global namespace" applies to variables that would normally be marked local by the complier. So, consider this notorious error, for example:

x = 1def foo():    x += 1    print(x)foo()

Would throw an unbound local error, but an equivalent class definition:

x = 1class Foo:    x += 1    print(x)

will print 2.

Basically, if there is an assignment statement anywhere in a class block, it is "local", but it will check in the global scope if there is an unbound local instead of throwing the UnboundLocal error.

Hence, in your first example, it isn't a local variable, it is simply a free variable, and the resolution goes through the normal rules. In your next two examples, you us an assignment statemnt, marking x as "local", and thus, it will be looked up in the global namespace in case it is unbound in the local one.