Creating a class within a function and access a function defined in the containing function's scope
Solution 1:
That's an artifact of Python's name resolution rules: you only have access to the global and the local scopes, but not to the scopes in-between, e.g. not to your immediate outer scope.
EDIT: The above was poorly worded, you do have access to the variables defined in outer scopes, but by doing x = x
or mymethod = mymethod
from a non-global namespace, you're actually masking the outer variable with the one you're defining locally.
In example 2, your immediate outer scope is the global scope, so MyClass
can see mymethod
, but in example 4 your immediate outer scope is my_defining_func()
, so it can't, because the outer definition of mymethod
is already masked by its local definition.
See PEP 3104 for more details about nonlocal name resolution.
Also note that, for the reasons explained above, I can't get example 3 to run under either Python 2.6.5 or 3.1.2:
>>> def myfunc():
... x = 3
... class MyClass(object):
... x = x
... return MyClass
...
>>> myfunc().x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in myfunc
File "<stdin>", line 4, in MyClass
NameError: name 'x' is not defined
But the following would work:
>>> def myfunc():
... x = 3
... class MyClass(object):
... y = x
... return MyClass
...
>>> myfunc().y
3
Solution 2:
This post is a few years old, but it is among the rare ones to discuss the important problem of scope and static binding in Python. However, there is an important misunderstanding of the author for example 3 that might confuse readers. (do not take as granted that the other ones are all correct, it is just that I only looked at the issues raised by example 3 in details). Let me clarify what happened.
In example 3
def myfunc():
x = 3
class MyClass(object):
x = x
return MyClass
>>> myfunc().x
must return an error, unlike what the author of the post said. I believe that he missed the error because in example 1 x
was assigned to 3
in the global scope. Thus a wrong understanding of what happened.
The explanation is extensively described in this post How references to variables are resolved in Python