This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Short Description of Python Scoping Rules
I wrote two simple functions:
# coding: utf-8
def test():
var = 1
def print_var():
print var
print_var()
print var
test()
# 1
# 1
def test1():
var = 2
def print_var():
print var
var = 3
print_var()
print var
test1()
# raise Exception
In comparison, test1() assigns value after print var, then raise an Exception: UnboundLocalError: local variable 'var' referenced before assignment, I think the moment I call inner print var, var has a value of 2, am I wrong?
Yes, you're incorrect here. Function definition introduces a new scope.
# coding: utf-8
def test():
var = 1
def print_var():
print var <--- var is not in local scope, the var from outer scope gets used
print_var()
print var
test()
# 1
# 1
def test1():
var = 2
def print_var():
print var <---- var is in local scope, but not defined yet, ouch
var = 3
print_var()
print var
test1()
# raise Exception
Related
From Python's Programming FAQ, this doesn't work as many people expect:
>>> squares = []
>>> for x in range(5):
... squares.append(lambda: x**2)
>>> squares[2]() # outputs 16, not 4
The following explanation is offered:
This happens because x is not local to the lambdas, but is defined in
the outer scope, and it is accessed when the lambda is called --- not
when it is defined.
This is fine. However, the explanation does not sound entirely correct to me. Consider this:
def buildFunction():
myNumber = 6 # Won't compile without this line
def fun():
return myNumber
return fun
def main():
myNumber = 3 # Ignored
myFun = buildFunction()
myNumber = 3 # Ignored
print(myFun()) # prints 6, not 3
This makes sense, but can someone please offer a more accurate/general definition of when variable binding of Python closures occurs?
Consider this:
def main():
def buildFunction():
def fun():
return myNumber
return fun
myNumber = 3 # can use this...
myFun = buildFunction()
myNumber = 3 # ... or this
print(myFun()) # prints 3 this time
This is more comparable to the lambda example because the closure function is nested within the scope that declares the variable of interest. Your example had two different scopes so had two, completely unrelated, myNumbers.
In case you haven't come across the nonlocal keyword, can you guess what this will print?
def main():
def buildFunction():
nonlocal myNumber
myNumber = 6
def fun():
return myNumber
return fun
myNumber = 3
myFun = buildFunction()
# myNumber = 3
print(myFun())
Every variable has a scope.
Name lookup (getting the value that the name points to) resolves by default to the most inner scope.
You can only override names in local scope or a containing scope(using the keywords nonlocal and global).
In your second example in main you assign myNumber to a different scope that your fun function can access.
squares = []
for x in range(5):
squares.append(lambda: x**2) # scope = global / lambda
print(squares[2]())
def buildFunction():
myNumber = 6 # scope = global / buildFunction
def fun():
return myNumber # scope = global / buildFunction / fun
return fun
myNumber = 1 # scope = global
def main():
myNumber = 3 # scope = global / main. Out of scope for global / buildFunction
myFun = buildFunction()
print(myFun())
When fun is called, Python looks at fun's local scope and can't find myNumber.
So it looks at its containing scope.
The buildFunction scope has myNumber in scope (myNumber = 6) so fun returns 6.
If buildFunction did not have myNumber in scope then Python looks at the next scope.
In my version the global scope has myNumber = 1
So fun would return 1.
If myNumber also does not exist in the global scope, a NameError is raised because myNumber could not be found in local scope nor any of its containing scopes.
I have written the following code in Python 3.6.2:
user=0
def test():
global user
d = locals()
exec('user=1', globals(), d)
test()
print(user)
I want to use variable user (it is global) in exec and change its value to 1 and in print(user) print its value, but it is printing 0.
How can fix it?
You need to declare the variable global in the executed code:
>>> user = 0
>>> def test():
... exec('global user; user=1', globals())
...
>>> test()
>>> print(user)
1
I'm trying to convert a String containing a Python variable assignment into an actual variable.
The following was working for me.
s = "VAR = [1,55]"
exec(s)
print(VAR)
But then when places this code in a function, VAR never gets defined.
def myFunction():
s = "VAR = [1,55]"
exec(s)
print(VAR)
myFunction()
I'm not sure what I am missing. Thanks in advance for the help!
Responses to a few of the questions...
Error message: "NameError: name 'VAR' is not defined"
Using: Python 3
You can also pass globals to exec:
def myFunction():
s = "VAR = [1,55]"
exec(s, globals())
print(VAR)
related
python 2.7
def myfunc():
v1 = 11
exec "v1 = 22"
print v1
myfunc() # 22
def myFunction():
VAR = None
s = "VAR = [1,55]"
exec(s)
print(VAR)
myFunction() # [1, 55]
OR
def myFunction():
#VAR = None
s = "VAR = [1,55]"
exec(s)
print(locals()["VAR"])
myFunction() # [1,55]
In Python 2.7 you can simply do:
>> s = "VAR=55"
>> exec(s)
>> VAR
55
If you need custom namespace do:
>> my_ns = {}
>> exec "VAR=55" in my_ns
>> my_ns["VAR"]
55
Similar applies for Python 3 but exec there is actually a function so exec(...) is to be used. For example:
>> s = "VAR=55"
>> exec(s)
>> VAR
55
When you use functions scope comes into play. You can use locals(), globals() or use your custom namespace:
>>def foo():
ns = {}
s = "VAR=55"
exec(s) in ns
print(ns["VAR"])
>>foo()
55
Is it possible to pass global variables through a function. For example
def start():
global var
if var == 0:
print("Error")
else:
while var> -1:
print(var)
var = var - 1
Your start function explicitly allows access to a global variable named var. As evidenced by your error, you have no such variable defined. Please initialize the variable before the function:
var = 25
def start():
global var
# the rest of your function
# goes here after global var
Could I set a variable inside a function scope, knowing that I sent this variable like a parameter..
See the example:
def test(param):
param = 3
var = 5
test(var)
print var
I want the value printed be 3, but it doesn't happen.
How can I do that?
Thanks..
You can return the value of param like this:
def test(param)
param = 3
return param
var = 5
var = test(var)
Or you can use a global variable.
Better to use return than a global:
def test(param):
param = 3
return param
var = 5
var = test(var)
print var
The global statement allows you to assign to variables declared outside a function's scope.
var = 5
def test():
global var
var = 3
test()
print var
However, I have found that I seldom need to use this technique. The functional programming model makes this less important.