exec() and variable scope [duplicate] - python

This question already has answers here:
How to get local variables updated, when using the `exec` call?
(3 answers)
Closed 3 years ago.
I'm sure this has been asked and answered, but I couldn't find it specifically:
I'm just picking up Python and I'm not understanding a variable scope issue.
I've simplified the problem to the following:
Case 1:
def lev1():
exec("aaa=123")
print("lev1:",aaa)
lev1()
Case 2:
def lev1():
global aaa
exec("aaa=123")
print("lev1:",aaa)
lev1()
Case 3:
def lev1():
exec("global aaa ; aaa=123")
print("lev1:",aaa)
lev1()
Case 1 and Case 2 have aaa undefined in the print statement.
Case 3 works. Where does aaa actually exist in Case 1 and Case 2?
Is there a way to access aaa in Case 1 without a global declaration?

From the docs:
Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.
In other words, if you call exec with one argument, you're not supposed to try to assign any variables, and Python doesn't promise what will happen if you try.
You can have the executed code assign to globals by passing globals() explicitly. (With an explicit globals dict and no explicit locals dict, exec will use the same dict for both globals and locals.)
def lev1():
exec("aaa=123", globals())
print("lev1:", aaa)
lev1()

Related

"local variable referenced before assignment" [duplicate]

This question already has answers here:
Assigning to variable from parent function: "Local variable referenced before assignment" [duplicate]
(5 answers)
Short description of the scoping rules?
(9 answers)
Closed 8 years ago.
I come from a land of heavy Java and PHP experience so when it comes to Python much of the rules do not make sense to me.
I have a recursive Fibonacci function below that spits out the error:
Traceback (most recent call last):
File "C:\Users\Nic\workspace\lab8\src\Main.py", line 26, in <module>
print fibcount(27),"took",calls,"calls."
File "C:\Users\Nic\workspace\lab8\src\Main.py", line 19, in fibcount
calls += 1
UnboundLocalError: local variable 'calls' referenced before assignment
Here is my code:
calls = 0
def fibcount(n):
calls += 1
if n < 2:
return (1,1)
f1,c1 = fibcount(n-1)
f2,c2 = fibcount(n-2)
return (f1+f2,c1+c2+1)
print fibcount(27),"took",calls,"calls."
In Java this would obviously work because calls is a global variable in respect to the function fibcount() so it confuses me that calls is somehow not in scope.
What am I doing wrong?
In Python, you need to declare global variables as being global inside functions which reassign them to a different value. You would use global for this:
def fibcount(n):
global calls
...
Otherwise, Python will treat the calls variable as if it were local.
Note however that you only need to do this for global variables which you reassign. Simply reading their values will work fine.
Also, reassigning global variables like this is considered ugly in Python and should be avoided whenever possible. Most of the time, you should stick to passing values to functions and then reassigning variables to their return values. If you need to maintain state, use a class.
The only time global variables are warranted in Python is when you want to have module-level constants. And in that case, the convention is that they should have all-caps names:
MYCONST = 12345

python variable scope in function [duplicate]

This question already has answers here:
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 8 years ago.
I have found a similar question Python variable scope error. It's related to immutable variable. But when I test mutable variable, I don't know how Python interpreter decides the scope of the variable.
Here's my sample code:
def test_immutable():
a = 1
b = 2
def _test():
print(a)
print(b)
a += 1
print(a)
_test()
def test_mutable():
_dict = {}
def _test():
print(_test.__dict__)
_dict['name'] = 'flyer'
print('in _test: {0}'.format(_dict['name']))
_test()
print(_dict['name'])
if __name__ == '__main__':
# test_immutable() # throw exception
test_mutable() # it's ok
Immutable vs mutable has nothing to do with variable scoping. Variables are just names, and always work the same way. Scoping is even decided at compile time, long before Python knows what you're going to assign to them.
The difference between your two functions is that the first one assigns directly to a with the += operator, which causes a to become a local. The second one assigns to a key inside _dict, which ultimately calls a method on the dict object, and doesn't affect the variable's scoping.

Python lambda's binding to local values [duplicate]

This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
The following code spits out 1 twice, but I expect to see 0 and then 1.
def pv(v) :
print v
x = []
for v in range(2):
x.append(lambda : pv(v))
for xx in x:
xx()
I expected python lambdas to bind to the reference a local variable is pointing to, behind the scenes. However that does not seem to be the case. I have encountered this problem in a large system where the lambda is doing modern C++'s equivalent of a bind ('boost::bind' for example) where in such case you would bind to a smart ptr or copy construct a copy for the lambda.
So, how do I bind a local variable to a lambda function and have it retain the correct reference when used? I'm quite gobsmacked with the behaviour since I would not expect this from a language with a garbage collector.
Change x.append(lambda : pv(v)) to x.append(lambda v=v: pv(v)).
You expect "python lambdas to bind to the reference a local variable is pointing to, behind the scene", but that is not how Python works. Python looks up the variable name at the time the function is called, not when it is created. Using a default argument works because default arguments are evaluated when the function is created, not when it is called.
This is not something special about lambdas. Consider:
x = "before foo defined"
def foo():
print x
x = "after foo was defined"
foo()
prints
after foo was defined
The lambda's closure holds a reference to the variable being used, not its value, so if the value of the variable later changes, the value in the closure also changes. That is, the closure variable's value is resolved when the function is called, not when it is created. (Python's behavior here is not unusual in the functional programming world, for what it's worth.)
There are two solutions:
Use a default argument, binding the current value of the variable to a local name at the time of definition. lambda v=v: pv(v)
Use a double-lambda and immediately call the first one. (lambda v: lambda: pv(v))(v)

Trying to understand function environments in Python [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to understand function environments (global, local). Specifically, I get very confused when there is a nested function that has already been defined globally, for example:
def g(x):
print(x)
def f(f):
f(1)
f(g)
Can someone please help me with this concept? I would greatly appreciate it.
Thanks.
Python uses dictionaries to keep local and global variables in. When looking up a variable reference, it will look into the local dict first. If you want to reference a variable in the global dictionary, put the global keyword in front of it.
Also see answers to this question for more elaborate info.
I agree with user18044, however, is your confusion about the ’f(f)’? I agree that can be really confusing, especially in a non typed language. The argument to ’f’ is a function handle that has a local type scope with name ’f’. The way python decides which ’f’ gets used is explained by 18044. Python looks at the name ’f’ on the function definition and the local parameter ’f’ takes precidence over the global name ’f’ just like would be done if we had a global variable ’dude’ and a local variable ’dude’ in a function. The local overrides the global. Hopes this helps, and makes sense. :-)
The locals for a function consist of everything that was passed in, and every variable that is assigned to and not explicitly tagged as global (or nonlocal in 3.x).
The globals consist of everything that can be seen at global scope, including the function itself.
When a name is referenced, it is looked up in the locals first, and then in the globals if not found in the locals.
When the statement f(g) is run, the statement itself is at global scope, so there are no locals. f and g are both found in the globals: they are both functions. The function defined by def f... is called, with the function defined by def g... being passed as an argument.
When f(f) runs, f is in the locals for the function. It is bound to the passed-in value, which is the function defined by def g.... The body of the function has the statement f(1). 1 is a constant and no lookup is required. f is looked up in the locals, and the passed-in function is found. It - being the function known at global scope as g - is called.
Thus g is, likewise, run with the value 1 bound to the local variable x. That is forwarded to the function print (in 3.x; in 2.x, print is a keyword, so print x is a statement), which prints the value 1.

Python variable scope in if-statements [duplicate]

This question already has answers here:
What's the scope of a variable initialized in an if statement?
(7 answers)
Closed 3 years ago.
In Python, are variable scopes inside if-statements visible outside of the if-statement? (coming from a Java background, so find this a bit odd)
In the following case, name is first defined inside the if-block but the variable is visible outside of the if-block as well. I was expecting an error to occur but 'joe' gets printed.
if 1==1:
name = 'joe'
print(name)
if statements don't define a scope in Python.
Neither do loops, with statements, try / except, etc.
Only modules, functions and classes define scopes.
See Python Scopes and Namespaces in the Python Tutorial.
Yes, in Python, variable scopes inside if-statements are visible outside of the if-statement.
Two related questions gave an interestion discussion:
Short Description of the Scoping Rules?
and
Python variable scope error
All python variables used in a function live in the function level scope. (ignoring global and closure variables)
It is useful in case like this:
if foo.contains('bar'):
value = 2 + foo.count('b')
else:
value = 0
That way I don't have to declare the variable before the if statement.

Categories

Resources