Python: local variable 'string' referenced before assignment - python

I was wondering why i was getting this error for adding a letter to this string from a function.
local variable 'string' referenced before assignment
CODE
def update_string():
string+='d'
string='s'
update_string()

You are accessing global variable, need to declare it:
def update_string():
global string # <<< declare `string` as global variable.
string+='d'
string='s'
update_varibles()

There is nowhere for the old 'string' to come from in the local scope of your function, so python assumes you're talking about the one from the outer scope.
Moreover, since strings are immutable the usual pattern is to create a new one and return it, so you might prefer to update your function interface to something more like:
def update_string(str_in):
return str_in + 'd'
And then you would use it instead like:
my_string = update_string(my_string)

You can access the variable from the outer scope inside the function, but you can't assign to it. So the following is a workaround without using global variables or inputs to the function:
def update_string():
updated=string+"d"
return updated
string="s"
string=update_string()

Related

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.

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.

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'

python static variables and methods

I know there have been several posts about this, but I am still confused. Am trying to use a static variable with initialization, and don't know how to do it. So what I have is a package 'config', which has a module the_config.py. What I would like is for this to be something like
# the_config.py
import yaml
user_settings=None
def initialize(user_settings_file)
with open(user_settings_file) as yaml_handle:
user_settings = yaml.safe_load(user_settings_file)
Then there would be a calling module as pipeline.py
#pipeline.py
import config.the_config as my_config
def main(argv):
...
my_config.intialize(user_settings_file)
print my_config.user_settings['Output_Dir']
But this doesn't work. How should I be doing this please?
Thanks in advance.
When you assign to user_settings, it is automatically treated as a local variable in the initialize function. To tell Python that the assignment is intended to change the global variable instead, you need to write
global user_settings
at the beginning of initialize.
In Python any variable that is assigned in the body of a function is considered a local variable, unless it's has been explicitly declared differently with either global or nonlocal declarations.
Python considers also assignment any "augmented-assignment" operator like += or /=.
The mandatory declaration of global that are modified is a (little) price to pay to the fact that in Python there is no need to declare variables.
It's also assumed that your code doesn't rely too much on mutating state in that is kept global variables so if your code requires a lot of global declarations then there's probably something wrong.
I can propose You some way to solve this.
First of all the root of your problem is creation of new local variable in your initialize function
user_settings = yaml.safe_load(user_settings_file)
As soon as there is equal sign right to variable name python create new variable in corresponding scope (in this case local for initialize function
to avoid this one can use following:
use global declaration
def initialize(user_settings_file)
global user_settings # here it is
with open(user_settings_file) as yaml_handle:
user_settings = yaml.safe_load(user_settings_file)
modify existing variable but not create new one
user_settings = {}
def initialize(user_settings_file)
with open(user_settings_file) as yaml_handle:
user_settings.update(yaml.safe_load(user_settings_file)) # here we modify existing user_settings
operate with module attribute (this one is quite tricky)
user_settings = {}
def initialize(user_settings_file)
with open(user_settings_file) as yaml_handle:
import the_config
the_config.user_settings = yaml.safe_load(user_settings_file)

Categories