How to refer global variable Python? - python

I am trying get the value of 'p1' variable outside a function. I have defined it as a global variable but I cannot reference is outside the function. It gives me error, "NameError: global name 'p1' is not defined"
Following is my code. Please let me know how can I get the value of global variable outside my function & also reference it in other function
#!/bin/usr/python
import subprocess
import string
def ping_check():
global p1
with open ('yst-host.txt') as hl:
for host in hl:
print host
p1 = subprocess.call("ping -c2 " + string.strip(host)+ "> /dev/null", shell=True)
print "Value of P1 is: ", p1
#ping_check()
print p1

In the code shown, you never actually call ping_check(), so your code is more or less equivalent to:
#!/usr/bin/env python
print p1
And then it's pretty clear that you're trying to use a global variable that doesn't exist yet.
Perhaps you should call your function? And make sure that hl is not empty? That way you'll have assigned to p1 at least once.
And for anyone wondering, here's a valid use of global in python. Note that we don't need to predefine a global variable, although that might be a good practice (so you can get a known value rather than a NameError).
def fun():
global p1
p1 = 3
fun()
print p1

This was going to be a comment, but it might actually be the answer.
As sharth points out, you don't need to predeclare a global variable to use it. However, it is added to globals() (and can be accessed without NameError outside the function) after you assign a value to it, not after the global statement. This means, that you should check if your code ever reaches the line with assignment.
Here's an example:
def more_fun():
global am_i_defined
print globals() #doesn't include am_i_defined
am_i_defined = True
print globals()
more_fun()
print am_i_defined

Related

Global Variable declaration

I am kind of a beginner with Python and have dealt with the concept of a global variable. When I thought I understood the concept, I saw a short code which proved me wrong:
message="global"
def enclosure():
message="enclosure"
def local():
global message
message="local"
local()
print(message)
print(message)
enclosure()
print(message)
The output of that is:
global
enclosure
local
I dont understand, why the second output is enclosure, because when you call the enclosure function, within this function the funciton local is called, in which the global variable message is set to "local", which then as of my understanding should be printed out at the end when calling the enclosure function (so i would expect global, local, local..).
So where is my thinking error?
When you assigned message="enclosure" in enclosure, you made message a local variable for that scope. It doesn't matter that the nested function changed the global message; enclosure didn't declare message global, so it maintains its own locally scoped variable independent of the global one (that local shares).
In general, you should try to avoid global variables if possible. There is usually a cleaner way to achieve what you want.
In your example, you have two string variables, both called message. One has the scope of the whole module, it is initially bound to the value "global" and then inside the local method it is rebound to the value "local".
The second variable is also called message and has the scope of the enclosure method. It is initially set to the value "enclosure" and is not modified.
Your first print call is at module scope, so prints the value of the module-scoped message, which is "global". Your second call is inside the enclosure so prints the value of the other variable which is "enclosure". And finally you print the value of the module-scoped message which has now been changed to the value "local".
In reality you have two variables, for clarity I added a suffix 1 and 2:
message1="global"
def enclosure():
message2="enclosure" # this is a new declaration, it is a new message.
def local():
global message1
message1="local"
local()
print(message2) # in this scope, only message2 is visible
print(message1)
enclosure()
print(message1)
So you see, you created two message, and you use at the second print the second variable named message
i hope this will help you:
def generate_closure(income_tax_rate = 0.33):
def this_is_closure_which_will_give_final_money(raw_income):
final_money = raw_income - (raw_income * income_tax_rate)
return final_money
return this_is_closure_which_will_give_final_money
standard_tax_calculator = generate_closure()
classic_salary = standard_tax_calculator(2000)
final_classic_money = print(classic_salary)
classic_salary_2 = standard_tax_calculator(2499)
final_classic_money_2 = print(classic_salary_2)
rich_people_tax_calculator = generate_closure(income_tax_rate = 0.50)
rich_salary = rich_people_tax_calculator(15000)
final_rich_money = print(rich_salary)
rich_salary_2 = rich_people_tax_calculator(19499)
final_rich_money_2 = print(rich_salary_2)
print("\n------------------------------")
def generate_closure(trapped):
def closure(x):
return trapped ** x
return closure
f = generate_closure(10)
print(f)
f(3)
print(f(3)) # f remember the value 10
del generate_closure
print(f(2)) # it still does work !
print(f.__closure__[0].cell_contents) # here is the hidden value
Here is a function which return another function.
A closure is not a variable.
A closure aims at avoid using global variable.
Take care not to use key-word the wrong way.
You can think to use closure when some argument it will use are known to be constant.

Return variable from a function

This section of a program I am writing is supposed to take the random choice and then print it outside the function (I can't print from within as I need the variable later).
I am sure there is a simple solution to this, but I am unsure what it is.
#python2
def CompTurn():
RandTurn = [Column1,Column2,Column3,Column4]
Choice = random.choice(RandTurn)
return(Choice)
print Choice
Thank you.
Add the line
Choice = CompTurn()
before your print statement. Because the variables you declare within the function are not known outside of it, you have to store (or print directly, but then you cannot store it) the returned variable in a new variable.
You have defined your function correctly, but you never executed it! (You'll see that if you make it print something as a diagnostic.) You must run it to get the result:
chosen = CompTurn()
print chosen
Note that I used a different variable name. You could use the same variable name as a variable in your function, but it's still a different variable than the one in your function.
It is also important to realize that your function returns a value, not a variable. You can assign the value to a variable (as above) or print it immediately.
print CompTurn()
About your program, you don't need the brackets for return. It's s statement, not a function.
def CompTurn():
RandTurn = [Column1,Column2,Column3,Column4]
Choice = random.choice(RandTurn)
return Choice
Shorter:
def CompTurn():
RandTurn = [Column1,Column2,Column3,Column4]
return random.choice(RandTurn)
To print the return value, You can save it in a variable and print it
ret = CompTurn()
print ret
Or print directly:
print CompTurn()

Dictionary not assigning value to variable

I am trying to assign a value from a dictionary to a variable but the variable remains unchanged. The value is another dictionary.
The code I used to generate the dictionaries can be found here: http://pastebin.com/Q2Hc8Ktp
I wrote it myself and tested it without this problem.
Here is the code snipit of me trying to copy the dictionary from the dictionary.
_classes = {}
def populateClasses():
print "Classes Exist"
cp = Preferences(''.join([resource_path,"resources.ini"]))
print cp
_classes = cp.getPreferences()['Classes']
populateClasses()
print _classes
When I print out cp it shows the correct data but when I try to print _classes it only shows {}
Note: printing _classes from within the function works as expected but not from outside the function. _classes is defined in the global scope
-Edit-
Here is also some sample data:
[Classes]
Wizard = Arcana, Bluff
Warrior = Endurance, Intimidate
Ranger = Nature, Perception
Bard = Heal, History
If you want to change the value of the global variable _classes, you need to use global:
def populateClasses():
global _classes # <<<<<< THIS
print "Classes Exist"
cp = Preferences(''.join([resource_path,"resources.ini"]))
print cp
_classes = cp.getPreferences()['Classes']
Without this, your method creates a separate local variable also called _classes. This variable goes out of scope as soon as your method returns.
Rather than global, you might use _classes.update(cp.getPreferences()['Classes']).
The rule for globals is that you need the global keyword if you write to it, but don't need it if you're just accessing the variable (even if that access is mutating the state). That's why my suggestion above doesn't need a global statement, and the original code does. Possibly that's also what happened when you "assigned lists to two variables" and didn't need global.

Globals as function input instead arguments

I'm just learning about how Python works and after reading a while I'm still confused about globals and proper function arguments. Consider the case globals are not modified inside functions, only referenced.
Can globals be used instead function arguments?
I've heard about using globals is considered a bad practice. Would it be so in this case?
Calling function without arguments:
def myfunc() :
print myvalue
myvalue = 1
myfunc()
Calling function with arguments
def myfunc(arg) :
print arg
myvalue = 1
myfunc(myvalue)
I've heard about using globals is considered a bad practice. Would it be so in this case?
It depends on what you're trying to achieve. If myfunc() is supposed to print any value, then...
def myfunc(arg):
print arg
myfunc(1)
...is better, but if myfunc() should always print the same value, then...
myvalue = 1
def myfunc():
print myvalue
myfunc()
...is better, although with an example so simple, you may as well factor out the global, and just use...
def myfunc():
print 1
myfunc()
Yes. Making a variable global works in these cases instead of passing them in as a function argument. But, the problem is that as soon as you start writing bigger functions, you quickly run out of names and also it is hard to maintain the variables which are defined globally. If you don't need to edit your variable and only want to read it, there is no need to define it as global in the function.
Read about the cons of the global variables here - Are global variables bad?
There are several reasons why using function arguments is better than using globals:
It eliminates possible confusion: once your program gets large, it will become really hard to keep track of which global is used where. Passing function arguments lets you be much more clear about which values the function uses.
There's a particular mistake you WILL make eventually if you use globals, which will look very strange until you understand what's going on. It has to do with both modifying and reading a global variable in the same function. More on this later.
Global variables all live in the same namespace, so you will quickly run into the problem of overlapping names. What if you want two different variables named "index"? Calling them index1 and index2 is going to get real confusing, real fast. Using local variables, or function parameters, means that they all live in different namespaces, and the potential for confusion is greatly reduced.
Now, I mentioned modifying and reading a global variable in the same function, and a confusing error that can result. Here's what it looks like:
record_count = 0 # Global variable
def func():
print "Record count:", record_count
# Do something, maybe read a record from a database
record_count = record_count + 1 # Would normally use += 1 here, but it's easier to see what's happening with the "n = n + 1" syntax
This will FAIL: UnboundLocalError: local variable 'record_count' referenced before assignment
Wait, what? Why is record_count being treated as a local variable, when it's clearly global? Well, if you never assigned to record_count in your function, then Python would use the global variable. But when you assign a value to record_count, Python has to guess what you mean: whether you want to modify the global variable, or whether you want to create a new local variable that shadows (hides) the global variable, and deal only with the local variable. And Python will default to assume that you're being smart with globals (i.e., not modifying them without knowing exactly what you're doing and why), and assume that you meant to create a new local variable named record_count.
But if you're accessing a local variable named record_count inside your function, Python won't let you access the global variable with the same name inside the function. This is to spare you some really nasty, hard-to-track-down bugs. Which means that if this function has a local variable named record_count -- and it does, because of the assignment statement -- then all access to record_count is considered to be accessing the local variable. Including the access in the print statement, before the local variable's value is defined. Thus, the UnboundLocalError exception.
Now, an exercise for the reader. Remove the print statement and notice that the UnboundLocalError exception is still thrown. Can you figure out why? (Hint: before assigning to a variable, the value on the right-hand side of the assignment has to be calculated.)
Now: if you really want to use the global record_count variable in your function, the way to do it is with Python's global statement, which says "Hey, this variable name I'm about to specify? Don't ever make it a local variable, even if I assign to it. Assign to the global variable instead." The way it works is just global record_count (or any other variable name), at the start of your function. Thus:
record_count = 0 # Global variable
def func():
global record_count
print "Record count:", record_count
# Do something, maybe read a record from a database
record_count = record_count + 1 # Again, you would normally use += 1 here
This will do what you expected in the first place. But hopefully now you understand why it will work, and the other version won't.
It depends on what you want to do.
If you need to change the value of a variable that is declared outside of the function then you can't pass it as an argument since that would create a "copy" of that variable inside the functions scope.
However if you only want to work with the value of a variable you should pass it as an argument. The advantage of this is that you can't mess up the global variable by accident.
Also you should declare global variable before they are used.

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()

Categories