Python - UnboundLocalError: local variable referenced before assignment` - python

I'm writing a Python 3.6 script that works with Tkinter and an SQLite 3 database, but I get this error:
if "fImage" in globals() and not(fImage==None):
UnboundLocalError: local variable 'fImage' referenced before assignment
The interested code is this:
from tkinter import *
from ttk import *
from tkinter import Toplevel, Tk
import sqlite3 as sql
def Salvataggio(mode,nome,cognome,sitoweb,email,idx):
conn=sql.connect(os.path.join(path, fn_prof),isolation_level=None)
c=conn.cursor()
if mode=="add":
if "fImage" in globals() and not(fImage==None):
c.execute("INSERT INTO prof VALUES ('{}','{}','{}','{}','{}','{}')".format(len(prof.keys())+1,nome.get(),cognome.get(),fImage,sitoweb.get(),email.get()))
else:
c.execute("INSERT INTO prof VALUES ('{}','{}','{}','{}','{}','{}')".format(len(prof.keys())+1,nome.get(),cognome.get(),"",sitoweb.get(),email.get()))
del fImage
wa.destroy()
elif mode=="edit":
if "fImage" in globals() and not(fImage==None):
c.execute("""UPDATE prof
SET nome = '{}', cognome = '{}', imageURI='{}', web='{}', email='{}'
WHERE ID={}; """.format(nome.get(),cognome.get(),fImage,sitoweb.get(),email.get(),idx))
else:
c.execute("""UPDATE prof
SET nome = '{}', cognome = '{}', web='{}', email='{}'
WHERE ID={}; """.format(nome.get(),cognome.get(),sitoweb.get(),email.get(),idx))
del fImage
def selImmagine(bi):
if not("fImage" in globals()):
global fImage
fImage=askopenfilename(filetypes=[(_("File Immagini"),"*.jpg *.jpeg *.png *.bmp *.gif *.psd *.tif *.tiff *.xbm *.xpm *.pgm *.ppm")])
# other code...
Do you know how to solve this? The error results with the if and the elif in the salvataggio() function.
Thanks

Remove:
del fImage
parts, it tries to remove fImage whether or not it exists.
See below Minimal, Complete, and Verifiable example:
def func():
del variable_that_never_existed
func()

The proximal cause of your error is:
del fImage
which works like assignment, it causes fimage to be treated as local. Therefore, you are getting an unbound-local error, which makes sense, since you never assign to fImage in the first place in Salvataggio
Anyway, yours is a special case of the typical UnboundLocalError, because it didn't involve assignment to the variable to make it get marked as local. A common cause being a hidden assignment:
You get a plain name error if the variable is neither global nor local.
In [1]: def f():
...: if x in {}:
...: pass
...:
In [2]: f()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-2-0ec059b9bfe1> in <module>()
----> 1 f()
<ipython-input-1-80c063ba8db6> in f()
1 def f():
----> 2 if x in {}:
3 pass
4
NameError: name 'x' is not defined
However, the del marks the name as local:
In [3]: def f():
...: if x in {}:
...: pass
...: del x
...:
In [4]: f()
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-4-0ec059b9bfe1> in <module>()
----> 1 f()
<ipython-input-3-5453b3a29937> in f()
1 def f():
----> 2 if x in {}:
3 pass
4 del x
5
UnboundLocalError: local variable 'x' referenced before assignment
This is why your check:
if "fImage" in globals() and not(fImage==None):
is the line where it fails. I do not understand why you always are checking whether fimage is in globals(). Note, 'fimage' in globals() can be true while fimage is a local name... hence the unbound local.

Related

Python: NameError: name 'myvar' is not defined, when importing a library

I'm trying to create a function within a library, to be called from the main script, where the variables are established
Main script (\project1\script.py):
from mylib.dosum import *
myvar = 10
print(dosum(1000))
\project1\mylib\dosum.py:
def dosum(x):
global myvar
valuetoreturn = x+myvar
return valuetoreturn
However, I get the following error message
NameError Traceback (most recent call last)
<ipython-input-2-5c2b1d2cc456> in <module>
1 from mylib.dosum import *
2 myvar = 10
----> 3 print(dosum(1000))
~\Python-scripts\project1\mylib\dosum.py in dosum(x)
1 def dosum(x):
2 global myvar
----> 3 valuetoreturn = x+myvar
4 return valuetoreturn
NameError: name 'myvar' is not defined
Every module has its own global namespace. The myvar used by dosum is mylib.dosum.dusum; you are defining a new global in your script named myvar, not assigning to mylib.dosum.myvar.
Do this instead:
# Avoid "from ... import *"
import mylib.dosum
mylib.dosum.myvar = 10
print(mylib.dosum.dosum(1000))
There are two problems here:
First, that's not how to do the import. Try like this instead!
from mylib import dosum
Second, the error on myvar isn't due to your library missing! You are trying to sum a value (in this case 1000) to nothing, since myvar isn't initialized. I think your goal is to sum 10 and 1000, right? Then either you need to pass two parameters to your dosum() or you need to instantiate a variable somewhere and import it too, like this:
main.py:
from mylib import dosum
MY_VAR = 10
print(dosum(1000))
mylib.py:
from main import MY_VAR
def dosum(x):
valuetoreturn = x + MY_VAR
return valuetoreturn
..or, you set the global variable in your main, like so:
mylib.dosum.myvar = 10

Python3 method not callable due to UnboundLocalError

Take into account the following code:
def main():
print('Calling methodA()')
methodA()
print('Calling methodB(True)')
methodB(True)
print('Calling methodB(False)')
try:
methodB(False)
except UnboundLocalError as error:
print(f'--> "UnboundLocalError" raised: {error}')
def methodA():
print('Running methodA()')
print('"method_original" in globals(): ' + str('method_original' in globals()))
method_original()
def methodB(patch_function):
print(f'Running methodB({patch_function})')
print('"method_original" in globals(): ' + str('method_original' in globals()))
if patch_function:
method_original=method_patched
method_original()
def method_original():
print('Running method_original()')
def method_patched():
print('Running method_patched()')
if __name__ == '__main__':
main()
It produces the following output:
Calling methodA()
Running methodA()
"method_original" in globals(): True
Running method_original()
Calling methodB(True)
Running methodB(True)
"method_original" in globals(): True
Running method_patched()
Calling methodA(False)
Running methodB(False)
"method_original" in globals(): True
--> "UnboundLocalError" raised: local variable 'method_original' referenced before assignment
Which makes no sense because "method_original" is in globals(). This error can be fixed simply adding global method_original at the beginning of the methodB() but in some cases we have a lot of functions and it could be a pain in the ass to put all of them at the beginning of every method.
Are there any rules to avoid this behavior?
//BR!
Let me explain it in a simpler example :
def fn(a):
if a % 2 == 0:
x = a
return x
print(fn(10)) # Fine
print(fn(9)) # UnboundLocalError: local variable 'x' referenced before assignment
In compile time, when interpreter reaches the function, it sees that there is an assignment to x, so it marks x as a "local" variable. Then in "runtime" interpreter tries to find it only in local namespace ! On the other hand, x is only defined, if a is even.
It doesn't matter if it presents in global namespace, now I want to add a global variable named x, to my example:
def fn(a):
if a % 2 == 0:
x = a
return x
x = 50
print(fn(10)) # Fine
print(fn(9)) # UnboundLocalError: local variable 'x' referenced before assignment
Nothing changed. Interpreter still tries to find x inside the function in local namespace.
Same thing happened in your example.
This is to show which variables are "local":
def fn(a):
if a % 2 == 0:
x = a
return x
print(fn.__code__.co_varnames)
co_varnames is a tuple containing the names of the local variables
(starting with the argument names)
Solution:
Either use global (which I see you don't like) , or do not do assignment inside the function, for example change your methodB to :
def methodB(patch_function):
print(f'Running methodB({patch_function})')
print('"method_original" in globals(): ' + str('method_original' in globals()))
if patch_function:
method_patched()
else:
method_original()

Getting a "Key Error: var_cheeze_value11"

I'm making a program that makes variables with a base name and variables like their id and series.
I use vars()[str(name+id+serie)] to make them and make it a button using the tkinter module.
When I launch it, it works until it tries to .get() the value from it, saying
keyError (variable name)
I tried to change how it's named, making it int() or moving the .get() here and there but nothing works.
# -*- coding: utf-8 -*
from tkinter import *
import math
import random
fenetre = Tk()
fenetre.geometry("1000x1000")
kanvas=Canvas(fenetre, width=500, height=500, bg="white")
id = 0
serie = 1
idcounter=0
while 1:
print("serie =",serie)
def cheezegrater():
global serie,id,idcounter
vars()[str("var_cheeze_sum"+str(serie))]=0
for o in range(1,val+1):
print("var11 =",var_cheeze_value11.get())
vars()[str("var_cheeze_sum"+str(serie))] += vars()[str("var_cheeze_value"+str(id-val+o)+str(serie))].get()
kanvas.pack()
fenetre.mainloop()
vars()[str("nombre_de_formes"+str(serie))] =int(float(input("combien?")))
val = vars()[str("nombre_de_formes"+str(serie))]
for o in range(1,val+1):
id+=1
vars()[str("var_cheeze_value"+str(id)+str(serie))] = Entry(kanvas, width=10)
o+=1
vars()[str("var_cheeze_value"+str(id)+str(serie))].pack
kanvas.pack()
fenetre.mainloop()
Traceback (most recent call last):
File "C:\Users\Utilisateur\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/Users/Utilisateur/.PyCharmEdu2019.1/config/scratches/scratch_1.py", line 38, in cheezegrater
vars()[str("var_cheeze_sum"+str(serie))] += vars()[str("var_cheeze_value"+str(id-val+o)+str(serie))].get()
KeyError: 'var_cheeze_value11'
You're inside a function and therefore outside of the same namespace where vars() doesn't contain those variables. Have a look at this example:
x = 1
print('Outside', x, 'x' in vars())
def f():
global x
print('Inside', x, 'x' in vars())
f()
It prints:
Outside 1 True
Inside 1 False
As you can see, even though we have global x and can print its value, it's not a key in vars() inside the function.
Also: Why are global variables evil?
Why did you choose to use vars() in the first place? Maybe you could just use a separate dict object instead? There's a lot of information in this question Python: Using vars() to assign a string to a variable
An improved version of the example from above might look like this:
data = {}
key = 'x'
data[key] = 1
print('Outside', data['x'], 'x' in data)
def f(data):
print('Inside', data['x'], 'x' in data)
f(data)
Of course, instead of 'x', you can use your own keys like str("var_cheeze_sum"+str(serie)).

Python exec() function broken in versions above 2.7? Error: 'name' not defined

I've discovered a strange behaviour of python exec() function. Here is the code:
variables = {
('foo', 6),
('bar', 42)
}
def func():
for varData in variables:
varName, varValue = varData
localVarToEvaluate = varName + ' = varValue'
try:
#exec(localVarToEvaluate, globals(), locals())
exec(localVarToEvaluate)
except Exception as err:
print(str(err))
if varName not in locals():
print("Variable names '", varName, "can't be found in local scope!")
if 'foo' in locals():
print("'foo' OK:", foo) # exception here
else:
print("'foo' not available!")
if 'bar' in locals():
print("'bar' OK:", bar)
else:
print("'bar' not available!")
func()
I would expect variables foo and bar to be created and printed at the end by exec() call, which is the case with Python 2.7. Everything above (tested on 3.3, 3.4, 3.6, and 3.7) throws exception, that foo is not defined:
Exception has occurred: NameError
name 'foo' is not defined
Strange thing here is that foo and bar is seen by running locals(), globals() or dir() (also confirmed by if statements), however, it is not seen by the code/interpreter.
Even stranger, debugging this script and resolving any variable is successfull (I've set a breakpoint on # exception here and type foo in Debug window using VS Code. foo is correctly resolved with a value of '6'.
If the same code (stuff inside function func()) is not wrapped in function, this works as expected, foo and bar are printed out.
Any idea what is happening here?
UPDATE: I've further simplify this problem:
# take 1, create local variable 'foo' with value 6. Not in function.
varName = 'foo'
varValue = 42
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate)
except Exception as err:
print(str(err))
if 'foo' in locals():
# print(locals()['foo']) # (1)
# print(foo) # (2)
print("'foo' OK:", foo) # (3)
# take 2, create local variable 'bar' with value 42
def func2():
varName = 'bar'
varValue = 42
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate)
except Exception as err:
print(str(err))
if 'bar' in locals():
# print(locals()['bar']) # (1)
# print(bar) # (2)
#print("'bar' OK:", bar) # (3)
pass # uncomment any line above
func2()
When this code executes, first:
'foo' OK: 6
is printed, than this exception is raised:
Exception has occurred: NameError
name 'bar' is not defined
...
Note that both codes are identical, except that 'bar' variable is created inside function func2().
What I am interested in are not workarounds but explanation, why is this so and why points (1) works, while (2) and (3) does not. Note that bar variable is seen in locals(), while it is not accessible by directly calling it - but only if it is created inside function!
I've reported a bug on a Python Issue Tracker, and the official answer is:
This is currently by design, which means 3.8 is likely the only viable place it can change. It's also not Windows specific so I removed that component (people may remove themselves from nosy).
...
Currently it's basically a read-only proxy, as locals are optimized within functions which is why you can't see updates via the duct.
Bottom line, exec() used in this way is useless inside functions.
Lots of unclear issues about this question solved with OP. See answer edits. It boils down to (importing) hooking locals (variables, defs, classes) such that they are available for use inside a definition.
See answer below with inline comments what is what and why.
# take 1, create local variable 'foo' with value 6. Not in function.
# >>> code is executed in local-scope <<<
varName = 'foo'
varValue = 42
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate) # (0) dict item becomes {varName : varValue}
print (localVarToEvaluate) # (1) prints > foo = varValue < dict item
except Exception as err:
print(str(err))
if 'foo' in locals():
print(locals()['foo']) # (2) prints > 42 < value
print(foo) # (3) prints > 42 < value
print("'foo' OK:", foo) # (4) prints > 'foo' OK: 42 < stringtext, value
# take 2, create local variable 'bar' with value 42
def func2(self):
# >>> code executed inside function and not local-scope <<<
varName = 'bar'
varValue = 42
localVar2Evaluate = varName + ' = varValue'
try:
exec(localVar2Evaluate) # (5) dict item becomes {varName : varValue}
print (localVar2Evaluate) # (6) prints > bar = varValue < dict item
except Exception as err:
print(str(err))
print ('local-scope :', '\n', locals()) # (7) {'bar': 42, 'localVar2Evaluate': 'bar = varValue', 'varValue': 42, 'varName': 'bar'}
if 'bar' in locals():
print(locals()['bar']) # (1)
print(bar) # (2) < --- python is not looking here in the locals() but inside the def for variable `bar` which is not made unless you give it access (hook or reference) via e.g. self.
print("'bar' OK:", bar) # (3)
# pass # uncomment any line above
x = 'a scotch... lets drink.. mystery solved!'
bar = "the local 'bar' variable is now available inside def func2().. It is: %s" % x
func2(bar)
As you can see I (import) create a hook to a local variable with varName 'bar' to be used inside the definition using self. It can be any name t.b.h. See pydocs on self, etc.
The result:
bar = varValue
local-scope :
{'localVar2Evaluate': 'bar = varValue', 'varValue': 42, 'bar': 42, 'self': "the local 'bar' variable is now available inside def func2().. It is: a scotch... lets drink.. mystery solved!", 'varName': 'bar'}
42
the local 'bar' variable is now available inside def func2().. It is: a scotch... lets drink.. mystery solved!
'bar' OK: the local 'bar' variable is now available inside def func2().. It is: a scotch... lets drink.. mystery solved!
If print('\n\n', locals()) below func() you get the following printresult:
'bar': "the local 'bar' variable is now available inside def
func2().. It is: a scotch... lets drink.. mistery solved!"
'localVarToEvaluate': 'foo = varValue'
'varValue': 42
'foo': 42
'varName': 'foo'
'x': 'a scotch... lets drink.. mistery solved!'
'func2': "<"function func2 at 0x000002B070027F28">" # without " outside ">".
At bullet 7 you see func2 linked.
UPDATE 4:
Switching between python 2.7.16 and 3.5.2 revealed no change for the locals() dict and ONE change in the globals() dict as shown below.
In 2.7: 'variables': set([('bar', 42), ('foo', 6)])
In 3.5: 'variables': {('bar', 42), ('foo', 6)}
... this set() looks to me the reason why it no longer works what you addressed in 3.5.
I did test it with adapting your script:
import sys
print (sys.version)
variables = {('foo', 6), ('bar', 42)}
def func():
for varData in variables:
varName, varValue = varData
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate)
print ('t2\n', locals())
except Exception as err:
print(str(err))
if varName not in globals():
print("Variable names '", varName, "can't be found in global scope!")
if 'foo' in globals():
print("'foo' OK:", foo) # exception here
else:
print("'foo' not available!")
if 'bar' in globals():
print("'bar' OK:", bar)
else:
print("'bar' not available!")
print ('t1\n', globals())
func()
Then ... it could still be exec. So I disabled running func() and the difference in globals() remained. SO I think its a difference in globals() function, rather exec.

PDB: Variable can be printed but is undefined

It looks strange. A variable with a name classes is printed but is undefined when trying to execute filter(...) contruction.
Here is a code:
def start(self, tag, attrib):
classes = attrib[self._CLASS_ATTR] if self._CLASS_ATTR in attrib else None
if tag == self._TAG_P:
p = self._doc.add_paragraph('')
self._cur_p = p
if classes is not None:
alignments = [self._left_align, self._center_align, self._right_align]
import pdb; pdb.set_trace()
alignments = filter(lambda x: partial(x.is_in, classes), alignments)
if len(alignments) > 0:
p.alignment = alignments[0].get()
assert len(alignments) < 2
Pdb stops on it's break. When I try to execute filter():
(Pdb) print filter(lambda x: partial(x.is_in, classes), alignments)
*** NameError: global name 'classes' is not defined
But:
(Pdb) print classes
center title
(Pdb) classes
u'center title'
Why the filter(...) instruction could not be executed normally?
Let's reproduce it in short code:
from functools import partial
def f():
classes = 'my_classes'
def my_bool(obj, _):
return True
if classes is not None:
import pdb; pdb.set_trace() # point a
alignments = filter(lambda x: my_bool(x, classes), ['1', '2', '3'])
import pdb; pdb.set_trace() # point b
pass
f()
...
(Pdb) filter(lambda x: my_bool(x, classes), ['1', '2', '3'])
*** NameError: global name 'my_bool' is not defined
However, the command c (continue) of pdb in point a does not generate an exception.
pdb is an eval loop. An eval loop essentially takes what you write to the prompt line by line and eval(...)s it. This means it doesn't bind closure-scoped variables in defined functions (lambdas). eval (which is a function) has its own scope and doesn't participate in the closure you are evaluating in.
You can see the equivalent problem from this example code:
def f():
x = 1
return eval('lambda: x')
>>> f()()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <lambda>
NameError: name 'x' is not defined
An (unfortunate) workaround is to define any lambdas up-front and use them in your pdb expression.

Categories