I am wondering why the following program does not print 'b'. It is is very simple code; I think it must work; and do not know the reason why it doesn't.
def a():
if b > 10:
print 'b'
sys.exit(1)
# main
while 1:
a()
b += 1
b is global variable. Actual code is more complicated but the structure is the same as mine. I guess when I call a() function and if b is greater than 10, it shows 'b'. However, it does not go inside if-statement.
Would you help me out how to solve?
Thanks.
Globals are horrid learn not to use them, try something like this
import sys
def a(value):
if value > 10:
print value
print "Greater than 10!"
sys.exit(0)
b = 0
while True:
a(b)
b += 1
Another answers suggests not using globals, and I agree. If you still want to use globals, you should define b outside of the loop first.(if you do, then please post the complete code, because apart from that, it should work (and it does)).
Now, global b in the function definition is not necessary, because python guesses it is a global variable when you try to access it before assigning. But since it is not defined it raises an NameError:
NameError: global name 'b' is not defined
If you don't see that, so there's something else, you're not showing the actual code that has a problem.
This gives you in the end, something similar:
import sys
def a():
global b
if b > 10:
print 'b'
sys.exit(1)
b = 0
# main
while 1:
a()
b += 1
Global vars are not the usual way to go. You may prefer the usage of nested functions instead:
import sys
def outer(value=0):
count = [value]
print "started at:", count[0]
def inner(x=1):
print "current val:", count[0]
count[0] += x
if count[0] > 10:
print "stopped at:", count[0]
sys.exit(0)
return inner
f = outer(5)
while True:
f(1)
You need to define b before "+="ing it.
def a():
if b > 10:
print 'b'
sys.exit(1)
# main
b = 0 # HERE
while 1:
a()
b += 1
By the way, as many had told you: avoid globals.
just my 2 cents: forget global variables.
anyway, this should work
def a():
global b
if b > 10:
print 'b'
sys.exit(1)
EDIT FUUUUUUUUUUUUUUU
Although I fully agree with Jackob on how you should use functions arguments and avoid globals, just for the record, here's the solution with global:
def a():
global b
if b > 10:
print 'b'
sys.exit(1)
# main
b = 0
while 1:
a()
b += 1
Related
Consider this example:
def A():
b = 1
def B():
# I can access 'b' from here.
print(b)
# But can i modify 'b' here?
B()
A()
For the code in the B function, the variable b is in a non-global, enclosing (outer) scope. How can I modify b from within B? I get an UnboundLocalError if I try it directly, and using global does not fix the problem since b is not global.
Python implements lexical, not dynamic scope - like almost all modern languages. The techniques here will not allow access to the caller's variables - unless the caller also happens to be an enclosing function - because the caller is not in scope. For more on this problem, see How can I access variables from the caller, even if it isn't an enclosing scope (i.e., implement dynamic scoping)?.
On Python 3, use the nonlocal keyword:
The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope.
def foo():
a = 1
def bar():
nonlocal a
a = 2
bar()
print(a) # Output: 2
On Python 2, use a mutable object (like a list, or dict) and mutate the value instead of reassigning a variable:
def foo():
a = []
def bar():
a.append(1)
bar()
bar()
print a
foo()
Outputs:
[1, 1]
You can use an empty class to hold a temporary scope. It's like the mutable but a bit prettier.
def outer_fn():
class FnScope:
b = 5
c = 6
def inner_fn():
FnScope.b += 1
FnScope.c += FnScope.b
inner_fn()
inner_fn()
inner_fn()
This yields the following interactive output:
>>> outer_fn()
8 27
>>> fs = FnScope()
NameError: name 'FnScope' is not defined
I'm a little new to Python, but I've read a bit about this. I believe the best you're going to get is similar to the Java work-around, which is to wrap your outer variable in a list.
def A():
b = [1]
def B():
b[0] = 2
B()
print(b[0])
# The output is '2'
Edit: I guess this was probably true before Python 3. Looks like nonlocal is your answer.
No you cannot, at least in this way.
Because the "set operation" will create a new name in the current scope, which covers the outer one.
I don't know if there is an attribute of a function that gives the __dict__ of the outer space of the function when this outer space isn't the global space == the module, which is the case when the function is a nested function, in Python 3.
But in Python 2, as far as I know, there isn't such an attribute.
So the only possibilities to do what you want is:
1) using a mutable object, as said by others
2)
def A() :
b = 1
print 'b before B() ==', b
def B() :
b = 10
print 'b ==', b
return b
b = B()
print 'b after B() ==', b
A()
result
b before B() == 1
b == 10
b after B() == 10
.
Nota
The solution of Cédric Julien has a drawback:
def A() :
global b # N1
b = 1
print ' b in function B before executing C() :', b
def B() :
global b # N2
print ' b in function B before assigning b = 2 :', b
b = 2
print ' b in function B after assigning b = 2 :', b
B()
print ' b in function A , after execution of B()', b
b = 450
print 'global b , before execution of A() :', b
A()
print 'global b , after execution of A() :', b
result
global b , before execution of A() : 450
b in function B before executing B() : 1
b in function B before assigning b = 2 : 1
b in function B after assigning b = 2 : 2
b in function A , after execution of B() 2
global b , after execution of A() : 2
The global b after execution of A() has been modified and it may be not whished so
That's the case only if there is an object with identifier b in the global namespace
The short answer that will just work automagically
I created a python library for solving this specific problem. It is released under the unlisence so use it however you wish. You can install it with pip install seapie or check out the home page here https://github.com/hirsimaki-markus/SEAPIE
user#pc:home$ pip install seapie
from seapie import Seapie as seapie
def A():
b = 1
def B():
seapie(1, "b=2")
print(b)
B()
A()
outputs
2
the arguments have following meaning:
The first argument is execution scope. 0 would mean local B(), 1 means parent A() and 2 would mean grandparent <module> aka global
The second argument is a string or code object you want to execute in the given scope
You can also call it without arguments for interactive shell inside your program
The long answer
This is more complicated. Seapie works by editing the frames in call stack using CPython api. CPython is the de facto standard so most people don't have to worry about it.
The magic words you are probably most likely interesed in if you are reading this are the following:
frame = sys._getframe(1) # 1 stands for previous frame
parent_locals = frame.f_locals # true dictionary of parent locals
parent_globals = frame.f_globals # true dictionary of parent globals
exec(codeblock, parent_globals, parent_locals)
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),ctypes.c_int(1))
# the magic value 1 stands for ability to introduce new variables. 0 for update-only
The latter will force updates to pass into local scope. local scopes are however optimized differently than global scope so intoducing new objects has some problems when you try to call them directly if they are not initialized in any way. I will copy few ways to circumvent these problems from the github page
Assingn, import and define your objects beforehand
Assingn placeholder to your objects beforehand
Reassign object to itself in main program to update symbol table: x = locals()["x"]
Use exec() in main program instead of directly calling to avoid optimization. Instead of calling x do: exec("x")
If you are feeling that using exec() is not something you want to go with you can
emulate the behaviour by updating the the true local dictionary (not the one returned by locals()). I will copy an example from https://faster-cpython.readthedocs.io/mutable.html
import sys
import ctypes
def hack():
# Get the frame object of the caller
frame = sys._getframe(1)
frame.f_locals['x'] = "hack!"
# Force an update of locals array from locals dict
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),
ctypes.c_int(0))
def func():
x = 1
hack()
print(x)
func()
Output:
hack!
I don't think you should want to do this. Functions that can alter things in their enclosing context are dangerous, as that context may be written without the knowledge of the function.
You could make it explicit, either by making B a public method and C a private method in a class (the best way probably); or by using a mutable type such as a list and passing it explicitly to C:
def A():
x = [0]
def B(var):
var[0] = 1
B(x)
print x
A()
For anyone looking at this much later on a safer but heavier workaround is. Without a need to pass variables as parameters.
def outer():
a = [1]
def inner(a=a):
a[0] += 1
inner()
return a[0]
You can, but you'll have to use the global statment (not a really good solution as always when using global variables, but it works):
def A():
global b
b = 1
def B():
global b
print( b )
b = 2
B()
A()
Consider this example:
def A():
b = 1
def B():
# I can access 'b' from here.
print(b)
# But can i modify 'b' here?
B()
A()
For the code in the B function, the variable b is in a non-global, enclosing (outer) scope. How can I modify b from within B? I get an UnboundLocalError if I try it directly, and using global does not fix the problem since b is not global.
Python implements lexical, not dynamic scope - like almost all modern languages. The techniques here will not allow access to the caller's variables - unless the caller also happens to be an enclosing function - because the caller is not in scope. For more on this problem, see How can I access variables from the caller, even if it isn't an enclosing scope (i.e., implement dynamic scoping)?.
On Python 3, use the nonlocal keyword:
The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope.
def foo():
a = 1
def bar():
nonlocal a
a = 2
bar()
print(a) # Output: 2
On Python 2, use a mutable object (like a list, or dict) and mutate the value instead of reassigning a variable:
def foo():
a = []
def bar():
a.append(1)
bar()
bar()
print a
foo()
Outputs:
[1, 1]
You can use an empty class to hold a temporary scope. It's like the mutable but a bit prettier.
def outer_fn():
class FnScope:
b = 5
c = 6
def inner_fn():
FnScope.b += 1
FnScope.c += FnScope.b
inner_fn()
inner_fn()
inner_fn()
This yields the following interactive output:
>>> outer_fn()
8 27
>>> fs = FnScope()
NameError: name 'FnScope' is not defined
I'm a little new to Python, but I've read a bit about this. I believe the best you're going to get is similar to the Java work-around, which is to wrap your outer variable in a list.
def A():
b = [1]
def B():
b[0] = 2
B()
print(b[0])
# The output is '2'
Edit: I guess this was probably true before Python 3. Looks like nonlocal is your answer.
No you cannot, at least in this way.
Because the "set operation" will create a new name in the current scope, which covers the outer one.
I don't know if there is an attribute of a function that gives the __dict__ of the outer space of the function when this outer space isn't the global space == the module, which is the case when the function is a nested function, in Python 3.
But in Python 2, as far as I know, there isn't such an attribute.
So the only possibilities to do what you want is:
1) using a mutable object, as said by others
2)
def A() :
b = 1
print 'b before B() ==', b
def B() :
b = 10
print 'b ==', b
return b
b = B()
print 'b after B() ==', b
A()
result
b before B() == 1
b == 10
b after B() == 10
.
Nota
The solution of Cédric Julien has a drawback:
def A() :
global b # N1
b = 1
print ' b in function B before executing C() :', b
def B() :
global b # N2
print ' b in function B before assigning b = 2 :', b
b = 2
print ' b in function B after assigning b = 2 :', b
B()
print ' b in function A , after execution of B()', b
b = 450
print 'global b , before execution of A() :', b
A()
print 'global b , after execution of A() :', b
result
global b , before execution of A() : 450
b in function B before executing B() : 1
b in function B before assigning b = 2 : 1
b in function B after assigning b = 2 : 2
b in function A , after execution of B() 2
global b , after execution of A() : 2
The global b after execution of A() has been modified and it may be not whished so
That's the case only if there is an object with identifier b in the global namespace
The short answer that will just work automagically
I created a python library for solving this specific problem. It is released under the unlisence so use it however you wish. You can install it with pip install seapie or check out the home page here https://github.com/hirsimaki-markus/SEAPIE
user#pc:home$ pip install seapie
from seapie import Seapie as seapie
def A():
b = 1
def B():
seapie(1, "b=2")
print(b)
B()
A()
outputs
2
the arguments have following meaning:
The first argument is execution scope. 0 would mean local B(), 1 means parent A() and 2 would mean grandparent <module> aka global
The second argument is a string or code object you want to execute in the given scope
You can also call it without arguments for interactive shell inside your program
The long answer
This is more complicated. Seapie works by editing the frames in call stack using CPython api. CPython is the de facto standard so most people don't have to worry about it.
The magic words you are probably most likely interesed in if you are reading this are the following:
frame = sys._getframe(1) # 1 stands for previous frame
parent_locals = frame.f_locals # true dictionary of parent locals
parent_globals = frame.f_globals # true dictionary of parent globals
exec(codeblock, parent_globals, parent_locals)
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),ctypes.c_int(1))
# the magic value 1 stands for ability to introduce new variables. 0 for update-only
The latter will force updates to pass into local scope. local scopes are however optimized differently than global scope so intoducing new objects has some problems when you try to call them directly if they are not initialized in any way. I will copy few ways to circumvent these problems from the github page
Assingn, import and define your objects beforehand
Assingn placeholder to your objects beforehand
Reassign object to itself in main program to update symbol table: x = locals()["x"]
Use exec() in main program instead of directly calling to avoid optimization. Instead of calling x do: exec("x")
If you are feeling that using exec() is not something you want to go with you can
emulate the behaviour by updating the the true local dictionary (not the one returned by locals()). I will copy an example from https://faster-cpython.readthedocs.io/mutable.html
import sys
import ctypes
def hack():
# Get the frame object of the caller
frame = sys._getframe(1)
frame.f_locals['x'] = "hack!"
# Force an update of locals array from locals dict
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),
ctypes.c_int(0))
def func():
x = 1
hack()
print(x)
func()
Output:
hack!
I don't think you should want to do this. Functions that can alter things in their enclosing context are dangerous, as that context may be written without the knowledge of the function.
You could make it explicit, either by making B a public method and C a private method in a class (the best way probably); or by using a mutable type such as a list and passing it explicitly to C:
def A():
x = [0]
def B(var):
var[0] = 1
B(x)
print x
A()
For anyone looking at this much later on a safer but heavier workaround is. Without a need to pass variables as parameters.
def outer():
a = [1]
def inner(a=a):
a[0] += 1
inner()
return a[0]
You can, but you'll have to use the global statment (not a really good solution as always when using global variables, but it works):
def A():
global b
b = 1
def B():
global b
print( b )
b = 2
B()
A()
I want to call var d from b(). but I get this error. I have heard that you can have global variables which I tried but with no success.
Error:
Traceback (most recent call last):
File "C:/Users/user2/Desktop/def.py", line 9, in <module>
a()
File "C:/Users/user2/Desktop/def.py", line 3, in a
if d == 0:
NameError: name 'd' is not defined
Code:
def a():
if d == 0:
print(correct)
else:
print (not correct)
def b():
d = 0
a()
You can define the variable outside the function and it should work. Although it is better to pass as argument.
d=0
correct="It is correct"
notcorrect="It is not correct"
def a():
if d == 0:
print(correct)
else:
print(notcorrect)
a()
You can use variables of a "parent" scope, even if it's better to pass them to the method. Your function b() is never called in your example. And definitions in a function are just defined for this functions or functions called from there.
I would recommend you to read about scopes:
https://pythonspot.com/scope/ (there are tons of other tutorials out there, just use your search engine ;))
what you could do:
d = 0
a() # correct
what you could do as well:
def b():
d = 0
a()
b() # correct
but what you SHOULD do is probably something like:
def b():
d = 0
return d
def a(d):
...
a(b()) # correct
global variables exist in python, but especially for beginners it often seems to be an easy solution, but as soon as your code grows this can become very complex if not used carefully.. understanding scopes of variables and how to pass them into other functions is the way to go.
The code will definitely show an error because the variables created within the function are for that function only called local variables, and the variable created outside the function are called global variables.
hence,
you simply have to create the variable outside the function globally then it will not shows error.
def a(d):
if d == 0:
print("correct")
else:
print ("not correct")
#################
a(0)
or else you can use inbuilt function global() if you want to use the variable inside the different functions.
and make sure you have the functions as well.
In my program I need a counter, but it just counts to one and not higher. Here is my code:
# set a counter variable
c = 0
def counter(c):
c += 1
print(c)
if c == 10:
methodXY()
def do_something():
# here is some other code...
counter(c)
this is the important part of my code. I guess the problem is that the method counter() starts with the value 0 all the time, but how can I fix that? Is it possible that my program "remembers" my value for c? Hope you understand my problem. Btw: I am a totally beginner in programming, but I want to get better
If you want to use outer variable "c" inside your function, write it as global c.
def counter():
global c
c += 1
print(c)
if c == 10:
methodXY()
You always call the function with the value 0 (like you expected). You can return "c"
and call it again.
Look:
# set a counter variable
c = 0
def counter(c):
c += 1
print(c)
return c
def do_something(c):
c=counter(c)
return c
for i in range(10):
c=do_something(c)
def main():
a == 3
b = a + 1
c = b + 1
print(a)
if (a<0):
print(a<0)
print(c)
else:
print('a is not less than 0')
print(a)
I watched the khan academy video #1 on Python programming and tried to duplicate it but it kept on giving the error above.
Thanks for your help
I am a first time python user
You are not assigning to a; you are instead testing for equality with a double ==:
a == 3
Since you didn't assign anything to a yet to compare with 3, that results in a NameError.
Remove one = sign to assign instead:
a = 3
This all assumes that the rest of your code is indented correctly to match the rest of your function:
def main():
a = 3
b = a + 1
c = b + 1
print(a)
if (a<0):
print(a<0)
print(c)
else:
print('a is not less than 0')
print(a)
== is used for comparison tests. You need to use = for variable assignment:
a = 3
Also, as your code currently stands, the stuff outside of main will not be able to access a because it is local to the function. Hence, you need to indent it one level:
def main():
a = 3
b = a + 1
c = b + 1
print(a)
if (a<0):
print(a<0)
print(c)
else:
print('a is not less than 0')
print(a)
main()
I think you want the following code:
def main():
a = 3
b = a + 1
c = b + 1
print(a)
if (a<0):
print(a<0)
print(c)
else:
print('a is not less than 0')
print(a)
main()
You want the if statements to be inside the function that you're making, in this case main(). Otherwise, 'a' will not be defined because it is inside the function main(). Welcome to python, and to stack overflow!