Global Variable declaration - python

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.

Related

Confusing use of global in Mark Lutz's "Learning Python"

On page 551 of the 5th edition, there is the following file, named thismod.py:
var = 99
def local():
var = 0
def glob1():
global var
var+=1
def glob2():
var = 0
import thismod
thismod.var+=1
def glob3():
var = 0
import sys
glob = sys.modules['thismod']
glob.var+=1
def test():
print(var)
local(); glob1(); glob2(); glob3()
print(var)
After which the test is run in the terminal as follows:
>>> import thismod
>>> thismod.test()
99
102
>>> thismod.var
102
The use of the local() function makes perfect sense, as python makes a variable var in the local scope of the function local(). However I am lost when it comes to any uses of the global variables.
If I make a function as follows:
def nonglobal():
var+=1
I get an UnboundLocalError when running this function in the terminal. My current understanding is that the function would run, and first search the local scope of thismod.nonglobal, then, being unable to find an assignment to var in nonglobal(), would then search the global scope of the thismod.py file, wherein it would find thismod.var with the value of 99, but it does not. Running thismod.var immediately after in the terminal, however, yields the value as expected. Thus I clearly haven't understood what has happened with the global var declaration in glob1().
I had expected the above to happen also for the var = 0 line in glob2(), but instead this acts only as a local variable (to glob2()?), despite having had the code for glob1() run prior to the assignment. I had also thought that the import thismod line in glob2() would reset var to 99, but this is another thing that caught me off guard; if I comment out this line, the next line fails.
In short I haven't a clue what's going on with the global scope/imports here, despite having read this chapter of the book. I felt like I understood the discussion on globals and scope, but this example has shown me I do not. I appreciate any explanation and/or further reading that could help me sort this out.
Thanks.
Unless imported with the global keyword, variables in the global scope can only be used in a read-only capacity in any local function. Trying to write to them will produce an error.
Creating a local variable with the same name as a global variable, using the assignment operator =, will "shadow" the global variable (i.e. make the global variable unaccessible in favor of the local variable, with no other connection between them).
The arithmetic assignment operators (+=, -=, /=, etc.) play by weird rules as far as this scope is concerned. On one hand you're assigning to a variable, but on the other hand they're mutative, and global variables are read-only. Thus you get an error, unless you bring the global variable into local scope by using global first.
Admittedly, python has weird rules for this. Using global variables for read-only purposes is okay in general (you don't have to import them as global to use their value), except for when you shadow that variable at any point within the function, even if that point is after the point where you would be using its value. This probably has to do with how the function defines itself, when the def statement is executed:
var = 10
def a():
var2 = var
print(var2)
def b():
var2 = var # raises an error on this line, not the next one
var = var2
print(var)
a() # no errors, prints 10 as expected
b() # UnboundLocalError: local variable 'var' referenced before assignment
Long story short, you can use global variables in a read-only capacity all you like without doing anything special. To actually modify global variables (by reassignment; modifying the properties of global variables is fine), or to use global variables in any capacity while also using local variables which have the same name, you have to use the global keyword to bring them in.
As far as glob2() goes - the name thismod is not in the namespace (i.e. scope) until you import it into the namespace. Since thismod.var is a property of what is now a local variable, and not a global read-only variable, we can write to it just fine. The read-only restriction only really applies to global variables within the same file.
glob3() does effectively the same thing as glob2, except it references sys's list of imported modules rather than using the import keyword. This is basically the same behavior that import exhibits (albeit a gross oversimplification) - in general, modules are only loaded once, and trying to import them again (from anywhere, e.g. in multiple files) will get you the same instance that was imported the first time. importlib has ways to mess with that, but that's not immediately relevant.

Assignment to variable in indent

Very simple problem (At least I think so): So I have a global variable, in this case test, and I want to assign an other value to it in a function. This is my code:
test = "Hello"
def launch():
test = "F"
launch()
print(test)
I wanted test to equal "F", but it doesn't. Instead, the output of this is that test still equals "Hello". I assume it creates a variable inside the function and then assigns a value to it.
But why does this work then:
test = {
"?": "Hallo"
}
def launch():
test["?"] = "F"
launch()
print(test)
The output of this is how I wanted it to be: test["?"] is equal to "F".
How is this working and why isn't the first code example?
Is there any way to use the first code how I wanted it to work?
You need to add a global test line to the top of the function to tell it to reference an existing variable instead of creating a new one. It's ambiguous otherwise.
Why does the second one work though? Because it isn't ambiguous. From context, it knows that you must be referencing an existing variable instead of attempting to create a new one.
test["?"] = "F"
is essentially
test.__setItem__("?", "F")
and that only makes sense if test already exists. It knows that you aren't trying to create a new local variable.
The language only requires a global test statement in cases where it can't tell whether or not you want to use an existing variable or create a new one.
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, however, it’s assumed to be a local unless explicitly declared as global.
So, change it as follows:
test = "Hello"
def launch():
global test
test = "F"
In your second example you don't declare the dictionary (like test = {}). Hence, python looks for a global variable test. You can access global variables by:
def launch():
global test
test = "F"
In the first case, you're trying to access a global variable but you have also redeclared it as a local variable.
test = "Hello" #global variable by default.
def launch():
test = "F" # local variable by default. It's restricted to the function launch().
launch()
print(test) # Accessing global variable because print can't see test of launch.
test = "Hello" #global variable by default.
def launch():
global test
test = "F" # Accessing global value of test.
launch()
print(test) # Accessing global variable test.
In second case,you're assigning to a global variable, not redeclaring it as a local variable. There in lies the difference.
test = {'?':"Hello"} #global variable by default.
def launch():
test['?'] = "F" # global variable access by default. It's NOT restricted to the function launch().
launch()
print(test) # Accessing global variable.
In your first test, in your launch function, the test variable is recreated, with no link to the global function. It's a particularity of python.
If you wanted to change the global function you should have done like this :
def launch():
global test
test = 'F'
With your second test, test is a dictionary.
And yes, when you change a dictionary in a function without declaring it as a global variable, it changes the dictionary outside of the function as well.
If you want to know the real reason, it's way more complicated if you don't know C language... Python was programmed in C (for CPython at least), and in C, managing variables is very different than in Python.
In C, when you want to modify a variable in a function, you have to give to the function the memory address of the variable as a parameter (that variable is called a Pointer).
If you don't give the pointer of your global variable to the function where you want to modify it, it won't work.
When your launch function was called in your first example, test wasn't modified, because as you haven't declared test as global, python hasn't given the pointer of test to the launch function (only its value).
When you use dictionaries, Python will also give the value of the dictionary, but it will be a pointer to its elements. So you will be able to modify them.
That's why you can modify the elements in the dictionary, but you can't modify the dictionary. Example :
a = {"a":123, 'b':456}
def modif():
a = {"aa":123}
modif()
print(a)
results in:
{'a': 123, 'b': 456}
So the dictionary hasn't been modified. It works the same way with the lists (and I suppose with every iterable that support item assignment)
I tried to simplify, it's more complicated in reality, but it may teach you some thing I hope.

Error message saying variable not defined when it is. Python

I am trying to create a simple encryption program in python using functions but am having a problem where I get an error message when I run the program saying ('msgReversed' is not defined) when it is.
the program works by first reversing the users message and then shifting the letters to the value of the Key
alphabet=("abcdefghijklmnopqrstuvwxyz ")
def userInput():
plaintext=input("Enter message to encript")
k=int(input("Enter encription Key you want to use (1-25)"))
return (k,plaintext)
def reverseMsg(plaintext):
msgReversed=''
leng=len(plaintext)-1
for c in plaintext:
msgReversed+=plaintext[leng]
leng=leng-1
print(msgReversed)
return(msgReversed)
def encript(msgReversed,k):
cipher=''
for c in msgReversed:
if c in alphabet:
cipher+=alphabet[(alphabet.index(c)+k)%(len(alphabet))]
print(cipher)
(k,plaintext)=userInput()
reverseMsg(plaintext)
(cipher)=encript(msgReversed,k)
Error Message reads as follows`:
Line 26, in <module>
(cipher)=encript(msgReversed,k)
NameError: name 'msgReversed' is not defined
As mentioned in my comment, your variable msgReversed is not declared outside of your function, so it is not defined when you call it outside of it. In order to avoid posting duplicate answers, here is another approach:
I do not know if you have worked with classes before, but here is an example and pythons official documentation (https://docs.python.org/2/tutorial/classes.html)
class Encrypt:
def __init__(self):
(k,plaintext)=self.userInput()
self.reverseMsg(plaintext)
cipher =self.encript(self.msgReversed,k)
def userInput(self):
plaintext=input("Enter message to encript")
k=int(input("Enter encription Key you want to use (1-25)"))
return (k,plaintext)
def reverseMsg(self, plaintext):
self.msgReversed=''
leng=len(plaintext)-1
for c in plaintext:
self.msgReversed+=plaintext[leng]
leng=leng-1
print(self.msgReversed)
return(self.msgReversed)
def encript(slf, msgReversed, k):
alphabet=("abcdefghijklmnopqrstuvwxyz ")
cipher=''
for c in msgReversed:
if c in alphabet:
cipher += alphabet[(alphabet.index(c)+k)%(len(alphabet))]
print(cipher)
Encrypt()
As for Global variables, you can declare a global within a function. all you have to do is declare it global:
variable_name global
so your function with your variable msgReversed would be as follows:
def reverseMsg(plaintext):
global msgReversed
msgReversed = ''
leng=len(plaintext)-1
for c in plaintext:
msgReversed+=plaintext[leng]
leng=leng-1
print(msgReversed)
return(msgReversed)
Change your last few lines from this:
reverseMsg(plaintext)
(cipher)=encript(msgReversed,k)
To this:
(cipher)=encript(reverseMsg(plaintext),k)
In your last line you pass a variable called 'msgReversed' into your 'encript' function. However: msgReversed is only locally defined inside your 'reverseMsg' function. Variables can either be local variables that only live inside of a function. Or global variables, that live in the entire script. A simple workaround would be to make your msgReversed a global variable, by simply adding 'global' in front of the first line of your 'reverseMsg' function. Another solution in your first to last line:
msgReversed = reverseMsg(plaintext)
A simplified tutorial on this matter: http://www.python-course.eu/global_vs_local_variables.php
Added a simple example:
myname = "Marc"
def printName():
myname = "Sonder"
print (myname)
printName()
print (myname)
Outside of the function, the 'myname' function will yield "Marc". However inside the function, myname will yield "Sonder". If you would delete the first line, and try to execute the last line, to print the global version of 'myname', you will get the exact same error as you have got right now.
To grasp this I would copy this script, and see what changes when you comment certain parts out.
When you return the msgReversed variable from the reverseMsg() function, you need to assign it to a new variable in the outside scope.
msgReversed = reverseMsg(plaintext)
(cipher)=encript(msgReversed,k)
I suspect the confusion arises with the following line:
return msgReversed # Note, the brackets aren't required here
This returns from the function reverseMsg() while passing out the variable msgReversed. However, this variable isn't assigned anywhere by default — the name msgReversed is specific to the function. To store a value returned from a function you need to provide a variable name to store it in. Hence the following:
msgReversed = reverseMsg(plaintext)
...will store the value returned from your function in a new variable named msgReversed. You could also name that variable something else:
this_is_another_msgReversed = reverseMsg(plaintext)
If you don't provide a variable to assign the value to, it is simply lost:
reverseMsg(plaintext)
# No msgReversed variable here

Global array -- no need for "global" statement

I wrote this code:
sample_array = ones ([N, 3], dtype = float)
def get_training_set ():
r = rand (N, 2) * 2 - 1
sample_array[:,[0,1]] = r
return sample_array
I declared the sampling array outside, in order not to allocate it all the time, just to modify it -- the last coordinate is always 1.
Initially I expected that I have to insert a statement "global sample_array" in function, because I modify it, and consequently the evaluator should know that it's a global var.
But, to my surprise, it works well without "global". Why does it work ? Where/what is the definition of evaluation in this case ?
global is necessary if you are changing the reference to an object (e.g. with an assignment). It is not necessary if you are just mutating the object (e.g. with slice assignment like what you've done above).
The exact documentation is here.
The global statement is a declaration which holds for the entire current code block. It means that the listed identifiers are to be interpreted as globals.
So, with the global statement, you're telling python that the variable lives in the global context. If you assign to it, then you change the value in the global context.
If you don't use the global statement, python decides whether the variable is local or nonlocal. (In fact, python3.x added a nonlocal keyword). The variable is nonlocal if it appears first on the right side of an assignment, or if you do item assignment (x[...] = ...) or attribute assignment (x.whatever = ...). If the variable is local, that means that it was created in the function (or is an input argument). You can reassign directly to a local identifier and there's no problem. If the variable is non-local, you can mutate it, but you can't re-assign it because then python is unable to determine whether the variable is local or non-local.
I think it's because sample_array is not declared inside the function, but just write.
Python cannot find sample_array in side function namespace, it will find the outer namespace.
E.g.
a = []
def test1():
a.append(1) # will use the outer one
def test2():
a = []
a.append(1) # will use the inner one
Global, sometimes, for declare a global variable:
def declare_global():
global b # this should be global after 'declare_global()' is called
b = 1
print b # raise NameError: name 'b' is not defined
declare_global()
print b # will output '1'

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.

Categories