Reputation: 1204
I am trying to understand the variable scope in Python (3.x), but below is an example of code that does not work and I am not sure why.
def function_a(A):
function_b()
def function_b():
print(A)
function_a(1)
Which results in NameError: name 'A' is not defined
So, the way I would think it works is that function_a()
and function_b()
are definid. Afterwards I run function_a()
where A
gets assigned the value of 1.
So in the scope of function_a()
the variable A=1 exists.
Then function_b()
gets called and is meant to print the value of variable A
. A does not exist in the scope of function_b(). Hence I would expect it to look a level higher, which would be the scope of function_a()
because function_b()
is run within function_a()
.
But clearly, I am getting that wrong. What actually happens?
Upvotes: 2
Views: 378
Reputation: 16773
Just because you have called function_b
inside of function_a
doesn't mean it would inherit the scope of function_a
and for good reasons. The function gets the scope from where it's defined, not where it's called.
If you want to accomplish something like closures
you should try to define function_b
inside of function_a
.
def function_a(A):
def function_b():
print(A)
With that said, I don't really see a use case for a closure here. You're better off passing the variable as an argument. That way it would be more reusable and testable.
def function_a(A):
function_b(A)
def function_b(A):
print(A)
Upvotes: 6
Reputation: 1794
I assume that this occurs because python does not place the bindings to parameters in the same namespace that a variable binding receives. The parameter bindings exist only within the function's scope.
The proper way to achieve your effect is using python closures (which enclose their parent function's namespace):
def function_a(A):
def function_b():
print(A)
function_b()
function_a(1)
You may simply pass the value A
to both functions, but this may suggest that you should make a class containing A
(especially if A
is required by many functions):
class A(object):
def __init___(self, a):
self.a = a
def function_a(self):
self.function_b()
def function_b(self):
print(self.a)
foo = A(1)
foo.function_a()
Upvotes: 0
Reputation: 78564
Hence I would expect it to look a level higher, which would be the scope of
function_a()
becausefunction_b()
is run withinfunction_a()
It does look higher. But the scope of function_a
is not higher than that of function_b
. The scopes are somewhat independent. Don't confuse scoping hierarchies with stack frames. The next scope in the hierarchy is the module scope, which here, is the global scope; A
is not in the global scope.
To access A
in function_b
, you can pass it as a parameter to function_b
or define A
in the module scope.
Upvotes: 3
Reputation: 160687
What happens is, in function_b
, a search in the global scope is done and since the global scope doesn't define a name A
and no enclosing function scope exists, you get a NameError
.
If an enclosing scope existed:
def function_a(A):
def function_b():
print(A)
function_b()
function_a(1) # prints 1
Or a global name A
was defined:
A = 2
def function_a(A):
function_b()
def function_b():
print(A)
function_a(1) # prints 2 (finds global name A)
you'd get the result of A
printed since the look-up would succeed.
Upvotes: 1