global and local variables misconception - python

I have a question regarding the output from the following code:
def f():
global s
print(s)
s = "That's clear."
print(s)
s = "Python is great!"
f()
print(s)
The output is this:
Python is great!
That's clear.
That's clear.
My question is: Why is it the very last output (i.e. the third output) is also "That's clear" .
How come the third output is not "Python is great!" .
I thought the very last statement from the code (i.e. the print(s)) statement is outside the function f(). So shouldn't print(s) here looks at the s variable that is defined globally? in this case the globally defined variable s would refers to the value "Python is great!", isn't it? Sorry there must be some concepts I have mis-understand. I am very newbie to python. Could someone kindly explain this simple concept.

To see the output you do, the structure of you code has to be:
def f():
global s
print(s) # s outside the function
s = "That's clear." # new global s created
print(s) # print the new s
s = "Python is great!" # s before you call the function/get to s = "That's clear."
f() # f gets called and new global s is created
print(s) # you see the new global s created in the function
Making s global means you see it outside the scope of f, you have already executed the function by the time you reach the last print so now the s points to That's clear.
If you wanted to get the output you expected, you would pass s into the function and not use the global keyword so the s created in f would be accessible only in the scope of the function itself.
def f(s):
print(s)
s = "That's clear."
print(s)
s = "Python is great!"
f(s)
print(s)
This should be a good lesson on why using global is rarely a good idea.

Assuming you have declared the variable s = "Python is great!" globally.
You may not have indented the code properly, the below code:
def f():
global s
print(s)
s = "That's clear."
print(s)
s = "Python is great!"
f()
print(s)
Will give you the output
Python is great!
That's clear.
Python is great!
The code you have written should essentially be giving an infinite recursion and should reach the max recursion depth.
Indentation is very important in python, when you indent the function call f() and the statement print(s), python considers both of these statements to be a part of the function f(). When the statement f() is reached during the first function call, python will automatically call the function again and repeats the whole process. In reality, you will never be able to reach the third print statement.

Related

How do I make a variable created inside a function become global?

I have a function in a program that I`m working at and I named a variable inside this function and I wanted to make it global. For example:
def test():
a = 1
return a
test()
print (a)
And I just can`t access "a" because it keeps saying that a is not defined.
Any help would be great, thanks.
I have made some changes in your function.
def test():
# Here I'm making a variable as Global
global a
a = 1
return a
Now if you do
print (a)
it outputs
1
As Vaibhav Mule answered, you can create a global variable inside a function but the question is why would you?
First of all, you should be careful with using any kind of global variable, as it might be considered as a bad practice for this. Creating a global from a function is even worse. It will make the code extremely unreadable and hard to understand. Imagine, you are reading the code where some random a is used. You first have to find where that thing was created, and then try to find out what happens to it during the program execution. If the code is not small, you will be doomed.
So the answer is to your question is simply use global a before assignment but you shouldn't.
BTW, If you want c++'s static variable like feature, check this question out.
First, it is important to ask 'why' would one want that? Essentially what a function returns is a 'local computation' (normally). Having said so - if I have to use return 'value' of a function in a 'global scope', it's simply easier to 'assign it to a global variable. For example in your case
def test():
a = 1 # valid this 'a' is local
return a
a = test() # valid this 'a' is global
print(a)
Still, it's important to ask 'why' would I want to do that, normally?

Why inspect.stack() does not work properly?

I'm trying to write name of the current executed function. But it does not work properly.
When I put 'print inspect.stack()[0][3]' after the def func(), it works, but when I try to put this command after the if, it prints nothing.
import inspect
debug = True
def debug():
print inspect.stack()[0][3]
if debug==True:
print "test"
print inspect.stack()[0][3]
debug()
returns 'debug' but it should return
'debug'\n'test'\n'debug'
Where is the problem?
When you define the function:
def debug():
you are loosing the last reference to the previously created variable debug from the global scope. You redefine the debug variable from being a boolean holding True to a function reference. So the condition debug==True is not met (because debug is a function now, not a boolean). And thus only the first print statement works (see an illustrative demo).
This will work as intended, for example:
import inspect
debug = True
def f():
print inspect.stack()[0][3]
if debug==True:
print "test"
print inspect.stack()[0][3]
f()
This is a common mistake in Python, especially from people used to other languages, in which function names are treated in a special way. In Python they are not - after you define a function, you can use its name as any other variable. Which has many advantages, but as seen here sometimes can be confusing.
In python 3 and hight you need to use print () if. It becomes a syntax error and won't print any thing if you don't have the ()

Function Return But No Value

I have a function defined which includes a return statement but no value is handed back. My code is as follows:
def seed(addy):
# urllib2 stuff is here
seed_result = re.search('<td>Results 1 - \d+ of (\d+)',seed_query) # searches for '<td>Results 1 - x of y', captures 'y'
seed_result = seed_result.group(1) # this is 'y' from above
# there's a call to a different function here which works properly
# other stuff going on here pertaining to addy but seed_result still has my string
# now I want to return the seed_result string...
return seed_result
# ... some code outside of the seed function, then I call seed...
seed(addy)
print "Result is %s" % seed_result
I have tried this with and without defining seed_result outside of the function to "initialize" it but this has no impact on the outcome which is that my print statement at the end yields "Result is " - there's no seed_result. I have also wrapped seed_result in parenthesis in the return statement though I believe how I have it is correct. The parens didn't make a difference.
A set up a very basic, yet similar, function in the Python shell and called it as I do here but that works. Not sure what I'm missing.
Thanks for the feedback and guidance.
You're not using the return value (e.g. assigning it to a variable). Try this:
result = seed(addy)
print "Result is %s" % result
Two ways of solving this:
First, the proper, obvious, and easy way is actually using the returned value:
seedresult = seed(addy)
Or you use a global variable (bad style - avoid at any cost):
seedresult = None
def seed(addy):
global seedresult
...
This is caused by None being assigned to seed_result during the execution of your function.
As Jon Skeet identified, you are doing nothing with the return value of your function. You should also address the issues below, though.
In particular, you are doing nothing with the parameter addy, and searching a global variable seed_query. I imagine the behaviour you are seeing is a result of that.

Unbound Local error in Python I can't shake!

http://pastie.org/1966237
I keep getting an unbound local error. I don't understand why it occurs, if the program is running right, it should go straight into the second assignment of the print_et_list function within the main function, looping itself without actually looping. The program only quits using sys.exit() in the hey_user function.
I included the whole program for context, it isn't too long. Let me know if you want to have a look at the text files I use in the program, however I'm sure it's unlikely that it is the source of the problem.
UnboundLocalError happens when you read the value of a local variable before you set it. Why is score a local variable rather than a global variable? Because you set it in the function. Consider these two functions:
def foo():
print a
vs
def bar():
a = 1
print a
In foo(), a is global, because it is not set inside the function. In bar(), a is local. Now consider this code:
def baz():
print a
a = 1
Here, a is set within the function, so it's local. But it hasn't been set at the time of the print statement, so you get the UnboundLocalError.
You forgot to pass score into hey_user().
Looks like it's probably the score variable. It's a local in main(), but you try to reference it in hey_user().
If you want to make score a global variable, be sure to declare it with the global statement:
def main ():
global score
score = 0
question, solution = print_et_list()
scoresofar = hey_user (solution)
print "\nYour score is now", scoresofar
question, solution = print_et_list()

Simple Python variable scope

It seems to me that functions can reference variables outside of their scope but cannot set them. Is this correct? Am I understanding this right?
I also included the globals usage. I know they are bad ju-ju and will avoid them; I know how to get around this, but just wanted to be clear.
My example program:
import foo
# beginning of functions
# this one works because I look at the variable but dont modify it
def do_something_working:
if flag_to_do_something:
print "I did it"
# this one does not work because I modify the var
def do_something_not_working:
if flag_to_do_something:
print "I did it"
flag_to_do_something = 0
# this one works, but if I do this God kills a kitten
def do_something_using_globals_working_bad_ju_ju:
global flag_to_do_something
if flag_to_do_something:
print "I did it"
flag_to_do_something = 0
# end of functions
flag_to_do_something = 1
do_something_working()
do_something_not_working()
do_something_using_globals_working_bad_ju_ju()
Correct. Well mostly. When you flag_to_do_something = 0 you are not modifying the variable, you are creating a new variable. The flag_to_do_something that is created in the function will be a separate link to (in this case) the same object. However, if you had used a function or operator that modified the variable in place, then the code would have worked.
Example:
g = [1,2,3]
def a():
g = [1,2]
a()
print g #outputs [1,2,3]
g = [1,2,3]
def b():
g.remove(3)
b()
print g #outputs [1,2]
Yep, pretty much. Note that "global" variables in Python are actually module-level variables - their scope is that Python module (a.k.a. source file), not the entire program, as would be the case with a true global variable. So Python globals aren't quite as bad as globals in, say, C. But it's still preferable to avoid them.

Categories