This question already has an answer here:
Override global variable inside function not working with Spyder 4
(1 answer)
Closed 1 year ago.
This is probably something obvious, but I'm confused.
I have a Python script test.py:
def t():
print(a)
a = 1
t()
When I run it, it prints 1, as expected:
runfile('C:/Users/Dave/data/Code/Python/lib/test.py', wdir='C:/Users/Dave/data/Code/Python/lib')
1
But when I then interactively type "a = 999" and run t() again, I expect it to print 999. But it prints 1. Why?
runfile('C:/Users/Dave/data/Code/Python/lib/test.py', wdir='C:/Users/Dave/data/Code/Python/lib')
1
a = 999
t()
1
FWIW, I'm running iPython inside Spyder.
Am I correct to think this is strange and not what I should expect?
Screenshot (added):
They are not the same variables:
def t():
print(id(a))
a = 1
t()
>>> runfile('C:/Users/Dave/data/Code/Python/lib/test.py', wdir='C:/Users/Dave/data/Code/Python/lib')
xx
>>> a = 999
>>> print(id(a))
yy
>>> t()
xx
This is the default behavior of runfile. It run the code in different namespaces.
def runfile(filename=None, args=None, wdir=None, namespace=None, post_mortem=False, current_namespace=False):
Change the current_namespace to True if you want to run it in the current namespace.
Related
This question already has an answer here:
How do the scoping rules work with classes?
(1 answer)
Closed 2 years ago.
a = 0
b = 0
def test():
a = 1
b = 1
class Test:
print(a, b)
a = 2
test()
It gives
0 1
It should be
1 1
Why is this happening?
Inside the test function, you're not actually initializing a new Test object, so Python will read through the class definition to use it inside the function scope, so it does execute the print statement. The problem is that you are trying to change the value of a in the class scope and this generates that a take the previous value of a outside the function definition.
This question already has an answer here:
Eval/Exec with assigning variable - Python
(1 answer)
Closed 3 years ago.
First of all, yes I know what I'm doing is bad. It's part of a hacky project that I'm trying for fun.
In Python 2.7, you could do this:
def myfunc():
exec('a=3')
print('Result: a = {}'.format(a))
myfunc()
And get Result: a = 3
Not so in Python 3.6, where you'll get NameError: name 'a' is not defined.
I can try to work around this by doing:
def myfunc():
exec('globals()["a"]=3')
print('Result: a = {}'.format(a))
myfunc()
Which in Python 3.6 gives the desired Result: a = 3 (and yes, has dangerous consequences by modifying globals). But of course it fails in the following case:
def myfunc():
a=2
exec('globals()["a"]=3')
print('Result: a = {}'.format(a))
myfunc()
Where I get Result: a = 2. Swapping in exec('a=3') here will also give Result: a = 2.
Question: Is there any hack in Python 3 that effectively allows me to assign to a variable in a function body?
def myfunc():
exec('a=3', locals(), globals())
print('Result: a = {}'.format(a))
myfunc()
This question already has answers here:
In Python, variables inside if conditions hide the global scope even if they are not executed?
(4 answers)
Closed 4 years ago.
Today I'm reading python change log and meet the nonlocal keyword and did some experiment with it. I find a confusing situation where untriggered assignment will change the nonlocal keyword behavior, please see the example below.
def a():
x = 'a'
def b():
def c():
nonlocal x
x = 'c'
c()
b()
print(x)
a()
>>> python3 test.py
c
def a():
x = 'a'
def b():
def c():
nonlocal x
x = 'c'
c()
if False:
x = 'b'
b()
print(x)
a()
>>> python3 test2.py
a
You can saw that in test2.py, there is an untriggered assginment x = 'b' which changed the behavior of nonlocal.
Why this happened?
Python decides which variables are local to a function at compile time. x is assigned to within the function b, so it's local. That that branch is never actually reached at runtime is irrelevant and can't be decided in general.
So the x in c that is nonlocal is the next x in an outer scope, namely the one in b.
The alternative would be much more surprising -- consider what would happen if the if False: was instead if rand(10) == 6:. Then during the first call of b the nonlocal variable would refer to the outermost one, but randomly at some later call of b it would start referring to the other one!
The output of following code is
5
3
I am new to Python, could anybody explain to me why?
import sys
def Main():
str='1+2'
print eval(str)
class A:
def __init__(self):
self.x = 5
a = A()
print a.x
if __name__=="__main__":
Main()
Python code is evaluated from top-down, not from Main().
The interpreter sees the a = A() line first, and prints a.x which is equal to 5, then it checks for the if condition and prints eval(str) which is 3.
Hence the output,
5
3
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Creating lambda inside a loop
In the code below, invoking any member of the returned array of closures
prints the number 4.
def go():
x = []
for i in range(5):
def y(): print i
x.append(y)
return x
I would like each member of the closure to print the number that i was when the closure was defined.
One way around this is to use default arguments:
def y(i=i):
print i
Default arguments are evaluated when the function is created, not called, so this works as you'd expect.
>>> i = 1
>>> def y(i=i): print i
...
>>> i = 2
>>> y()
1
A little extra info just for fun:
If you're curious what the defaults are, you can always inspect that with the .func_defaults attribute (__defaults__ in python3.x):
>>> y.func_defaults
(1,)
This attribute is also writeable, so you can in fact change the defaults after the function is created by putting a new tuple in there.