The reason for this is because the scope of class C is actually different than the scope of def func - and the different defaulting behaviors of scopes that python has for resolving names.
Here is basically how python looks for a variable in a step-by-step guide:
- Look in current scope
- If current scope doesn't have it → use nearest enclosing scope
- If current scope has it, but not yet defined → use global scope
- If current scope has it, and already defined → use it
- Otherwise we blow up
(If you remove ytop you get the exception NameError: name 'y' is not defined)
So basically, when the interpreter looks at the following section of code it does this
class C:
print(x) # need x, current scope no x → default to nearest (xlocal)
print(y) # need y, current scope yes y → default to global (ytop)
# but not yet defined
y = 1
print(y) # okay we have local now, switch from global to local scope
Consider the following scenarios and the different outputs we would get in each case
1) class C:
print(x)
print(y)
>>> xlocal
>>> ylocal
2) class C:
y = 1
print(x)
print(y)
>>> xlocal
>>> 1
3) class C:
print(x)
print(y)
x = 1
>>> xtop
>>> ylocal