Here's my test script:
def main(): #global
n = 1
z = None
def addone(): #local
if not z:
n = n+1
addone()
print n
main()
I step into the addone() function once it hits the calling line.
At this point I can only see the variable z, but cannot see n.
Now, if n is referenced before assignment, shouldn't z be too?
Similarly, if I change n=n+1 to z='hi', I can no longer see z!
This is contrary to all my previous beliefs about local/global functions! The more you know, the more you know you don't know about Python.
Question(s):
Why can I see one but not the other?
Do I want to be prepending global to these variables I want to reassign?
The best solution is to upgrade to Python 3 and use in the inner function nonlocal n. The second-best, if you absolutely have to stick with Python 2:
def main(): #global
n = [1]
z = None
def addone(): #local
if not z:
n[0] += 1
addone()
print n[0]
main()
As usual, "there is no problem in computer science that cannot be solved with an extra level of indirection". By making n a list (and always using and assigning n[0]) you are in a sense introducing exactly that life-saving "extra level of indirection".
Okay, after some testing, I realised that it all has to do with the reassignment of variables.
for example:
def main(): #global
n = 1
z = None
def addone(): #local
if not z:
x = n+1
addone()
print n
main()
Now shows both n and z when I am inside the addone() function. This is because I am no longer trying to reassign n, makes sense to me so as to protect global variables from manipulation if one so happens to use similar names in local functions.
Related
I'm learning Python and I'm trying to understand this line if I call f(-1):
x = 0
def f(x):
if x < 0:
return g(-x)
else:
return g(x)
def g(x):
return 2*x + 3
If I call f(-1) I get 5. But I incorrectly interpret that I would get 1. This is my interpretation process:
Since x=-1 it should return g(-x). There is no def g(-x) though. However if it returns def g(x) then we should get 2*x+3, which is 1?
Don't know where I misunderstand.
Thanks
Think of g as the function and x as input to the function.
Furthermore, x is also just like any other variable name.
This means I could instead rename the x variable in the g function to anything I want.
I could also call g anything I want.
Example:
def f(x):
if x < 0:
return grumpy_function(-x)
else:
return grumpy_function(x)
def grumpy_function(cool_value):
return 2*cool_value + 3
Now try to walk through the logic using these above functions...
f(-1) causes the if statement x<0 to be true.
So we will execute the line return grumpy_function(-x)
We know that x=-1, so this means -x = -(-1) = 1.
Therefore cool_value is actually 1 not -1.
Now go to grumpy_function: 2*1+3 = 5.
when call g(-x), in your case, it equals g(-(-1)), which is g(1)
When you specify def f(x) or def g(x), you're saying that, in the following context, x is going to be the name for the actual parameter of these two methods, regardless of the x=0 defined outside.
That being said, the following lines are equivalent:
f(-1)
g(1) # because if x < 0 is True
2 * 1 + 3
5
From your code, it is not exactly clear to me which of the xes you'd like to refer to the global x=0 and which of them should refer to the function's parameter, like -1 in your example. You should make this distinction yourself and name them differently, for example, x and y. As far as I know, if you name your function parameters the same as your global variables, you lose access to the global variables from within the function body (except for globals tricks).
So I wrote this fragment of code inside one of my projects, and defined n to be a boolean value True. Then, I used it to make a toggle case of a pause/resume button. For some reason, I get the error for using n in the if statement before allegedly assigning it inside the if and else code, although I already assigned it above the whole function.
Can somebody explain this error? And maybe suggest a way to fix it?
n = True
def pauseresume():
if n:
pauseb.configure(text="Resume")
n = False
else:
pauseb.configure(text="Pause")
n = True
You can not use global var in a function
solution:
def pauseresume():
global n
if n:
...
For detail, click
Using global variables in a function.
If you want to use a global variable, you need to explicitely use it via global keyword.
n = True
def pauseresume():
global n
pauseb.configure(text="Resume" if n else "Pause")
n = not n # switch to other bool value
Suppose that I'm required to run a function with a loop in it until I meet a condition. For the function to work right, I'm only allowed to return one value in the function, but once the condition clears, I want to bring some of the calculations I performed into the global scope. I'm not allowed to use the return command to do this, so I decided to globalize the variables in post. This raises a warning, but seems to work alright. Is this the best way to do things?
Here's an example:
def check_cond(x,cond):
return (x - cond,3)
def loop(x,func):
relevant_value = 0
while x > 0:
local_expensive_calculation = 1 #use your imagination
x = func(x,local_expensive_calculation)[0]
relevant_value += func(x,local_expensive_calculation)[1]
if x == 0:
global local_expensive_calculation
return relevant_value
x = 4
loop(x,check_cond)
#then do stuff with local_expensive_calculation, which is now global
This may be slightly abusing the system but you can set your variable as an attribute of the function, and then access it later through that namespace:
def check_cond(x,cond):
return (x - cond,3)
def loop(x,func):
relevant_value = 0
while x > 0:
local_expensive_calculation = 1 #use your imagination
x = func(x,local_expensive_calculation)[0]
relevant_value += func(x,local_expensive_calculation)[1]
if x == 0:
loop.local_expensive_calculation = local_expensive_calculation
return relevant_value
x = 4
loop(x,check_cond)
print loop.local_expensive_calculation
If you absolutely insist on having it as a global, one way you can do that is by changing the line:
global local_expensive_calculation
to:
globals()['local_expensive_calculation'] = local_expensive_calculation
It makes your SyntaxWarning disappear.
I don't know much about the context and it appears you want a Python 2.7 answer (Python 3.?) has nonlocal.
Bear in mind that the while statement can also have a else clause
You can write:
while x>0:
# do calculation and stuff
else:
# make calculation result global
PS: There's a typo in your assignment to x: (calcuation --> calculation)
I have a function that returns a number. I want to assign a variable to have this value, but python gives a runtime error when I say temp = foo(i, j) : NameError: name 'foo' is not defined. Note that I've changed the function bodies of bar and foo around, obviously having a function that just returns 1 is useless, but it doesn't change my error.
sum = 0
for i in range(2, 100):
for j in range(2, i):
temp = foo(i, j)
if (temp > 100):
sum = sum + 1
print sum
def bar (n, a):
r = 1
return r
def foo (n, a):
s = bar(n, a)/factorial(5);
return s
def factorial (n):
r = 1
for i in range (2, n + 1):
r *= i;
return r
Names in Python do not exist until they are bound. Move the def foo(...): block above the code that uses foo().
Your definition of foo is AFTER you use it in the file. Put your function definition above the for loop.
As per other answers, your issue is the order in which you run your code: foo hasn't been defined yet when you first call it. Just wanted to add a comment about best practices here.
I always try to put everything in a function and then call any scripts at the bottom. You've probably encountered this pattern before, and it's a good habit to get into:
CONSTANT = 5
def run():
for i in xrange(CONSTANT):
print foo(i) # whatever code you want
def foo(n):
# some method here...
pass
if __name__ == "__main__":
run()
if you run this with python script.py or by hitting f5 in idle, run() will be executed after everything is defined.
By following this pattern you don't have to worry about the order you define your functions in, and you get the added benefit of being able to import foo with other functions without having your script execute during the import, which is probably not a desired behavior.
When I call the function "G()" which returns two values: p_T and q_T twice (see below) but using the same style, that's, P_T, neg = G(); U, Ign = G() and print sums of P_T and U, I get two different answers! Another thing is that both answers are incorrect!
I have only included part of the code which can simply aid in explaining the idea. The block of statements within the function G() under the for loop is executed N times as the loop suggests. Is there something being compromised by global variables declaration?
Any suggestion of what is wrong and how to fix it is appreciated!
def G():
global p_T; global q_T
for n in range(N):
p_T = U_T(EvolveU_T(p_T))
q_T = V_T(EvolveV_T(q_T))
return p_T, q_T
P_T, neg = G()
print sum(P_T)
U, Ign = G()
print sum(U)
You have global state. You mutate global state. Then you mutate it again, starting where you left off. So P_T is a result after N operations, and U is a result after 2N operations.
Don't use global state.
Because p_T and q_T are globals, their scope is not local to the function. So it's no surprise that you get two different answers after calling the function twice. Here's a simple example that demonstrates what's going on:
class C:
foo = ''
def __repr__(self):
return self.foo
x, y = C(), C()
def F():
global x
global y
x.foo += 'x'
y.foo += 'y'
return (x, y)
print F()
print F()
The globals x and y maintain their values because they are not scoped to the function. If they were declared and initialized inside the function without the global modifiers, you'd see (x, y) twice. But instead you see:
(x, y)
(xx, yy)
Generally globals are considered bad programming practice as they can lead to a confusing amount of state which is not localized to the function under consideration, as you've discovered.