I made an error while defining a function within a class, yet it doesn't change how the code operates during runtime.
The error I made was using a global variable when I mean to use an instanced variable.
What I meant to write was:
self._map_data[screen_pos_layer][y][x] = selected_material
Instead, I wrote:
map_data[screen_pos_layer][y][x] = selected_material
However, the intended functionality (change the color of an LED) doesn't change, no matter if it's the instanced variable or the global variable. The function that actually writes the color into the LED is in a different class.
I thought that could only happen if I include global <variable> ? I have very little experience with Python but I'm sure this was true.
class Tools(object):
def __init__(self, _map_data):
self._map_data = _map_data
def paint(self, event):
if selected_tool == select_paint and selected_color != -1:
for j in range(cursor_size_y):
for i in range(cursor_size_x):
y = screen_pos_y + cursor_pos_y + j
x = screen_pos_x + cursor_pos_x + i
map_data[screen_pos_layer][y][x] = selected_material
else:
return
moveCursor(event)
tools = Tools(map_data)
# this is a Tkinter object
window.bind_all("<Control-Up>", tools.paint)
I tried searching for this but I could only find posts about people wanting to use a global variable in a class, I specifically am trying not to.
Evidently your code has previously created a global map_data variable, so the code you're showing is not re-creating the map_data variable, it is only modifying an element of the existing variable. The existing variable is found via regular name lookup, and so in this case it is found in the global context.
Related
I was define a global variables which I wanted to change / give an actual value in a function.
When I tried to run it, I had an error message that informing the global variable is undefined.
please support, thanks. this is my code:
script_name = 'R2M_delayer.py'
recipe_name = 'R2M_E2E_delayer_NR_Ver_5.1'
global images
global metrology_images
logged_date = str(datetime.datetime.now()).split()[0]
NR_log = 'NR_' + logged_date + '.log'
images_output_dir_path = '/usr/local/insight/results/images/toolsDB/lauto_ptest_s' + str(datetime.datetime.now()).split()[0] + '/w3'
metro_images_dir_path = find_dir_path_delayer.get_delayer_images_dir_path()
metro_callback_dir_path = '/usr/local/disk2/unix_nt/R2M/RecipeRun'
def images_check():
estimated_num_of_images = 6640 # Hard codded for Sanity wafer #3
Actual_Images_List = os.listdir(images_output_dir_path)
images = len(Actual_Images_List)
if images >= estimated_num_of_images or images < 7000:
return True, images
print("\nImages quantity is not equal to the actual images in results folder.\n")
return False
print(' ' + str(images) + ' images were send.\n')
Problem has solved. I defined my global variables as fields in class and I was revalued that values of the fields in the functions.
The global keyword goes inside the function. That allows you to call that variable outside the function. If you declare the variable outside the function, you don't need it. By the way, you're returning images anyway. It is much better to return the value instead of modifying global variables, because it may return its reference instead. Global variables are not a good practice because it can """mess up""" with your allocated local memory for your program. I recommend using the garbage collector library gc.collect() to collect any data of a global variable you are not using or managing.
Declare global variables inside function definition, otherwise the scope of variables in function is always local.
To avoid "variable is not defined" error you can initiate them in the main code with some default value, e.g., images = None.
Agree with previous answer, try to not use global variables.
This question already has answers here:
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 6 months ago.
I am using the PyQt library to take a screenshot of a webpage, then reading through a CSV file of different URLs. I am keeping a variable feed that incremements everytime a URL is processed and therefore should increment to the number of URLs.
Here's code:
webpage = QWebPage()
fo = open("C:/Users/Romi/Desktop/result1.txt", "w")
feed = 0
def onLoadFinished(result):
#fo.write( column1[feed])#, column2[feed], urls[feed])
#feed = 0
if not result:
print "Request failed"
fo.write(column1[feed])
fo.write(',')
fo.write(column2[feed])
fo.write(',')
#fo.write(urls[feed])
fo.write(',')
fo.write('404,image not created\n')
feed = feed + 1
sys.exit(1)
save_page(webpage, outputs.pop(0)) # pop output name from list and save
if urls:
url = urls.pop(0) # pop next url to fetch from list
webpage.mainFrame().load(QUrl(url))
fo.write(column1[feed])#,column2[feed],urls[feed],'200','image created','/n')
fo.write(',')
fo.write(column2[feed])
fo.write(',')
#fo.write(urls[feed])
fo.write(',')
fo.write('200,image created\n')
feed = feed + 1
else:
app.quit() # exit after last url
webpage.connect(webpage, SIGNAL("loadFinished(bool)"), onLoadFinished)
webpage.mainFrame().load(QUrl(urls.pop(0)))
#fo.close()
sys.exit(app.exec_())
It gives me the error:
local variable feed referenced before the assignment at fo.write(column1[feed])#,column2[feed],urls[feed],'200','image created','/n')
Any idea why?
When Python parses the body of a function definition and encounters an assignment such as
feed = ...
Python interprets feed as a local variable by default. If you do not wish for it to be a local variable, you must put
global feed
in the function definition. The global statement does not have to be at the beginning of the function definition, but that is where it is usually placed. Wherever it is placed, the global declaration makes feed a global variable everywhere in the function.
Without the global statement, since feed is taken to be a local variable, when Python executes
feed = feed + 1,
Python evaluates the right-hand side first and tries to look up the value of feed. The first time through it finds feed is undefined. Hence the error.
The shortest way to patch up the code is to add global feed to the beginning of onLoadFinished. The nicer way is to use a class:
class Page(object):
def __init__(self):
self.feed = 0
def onLoadFinished(self, result):
...
self.feed += 1
The problem with having functions which mutate global variables is that it makes it harder to grok your code. Functions are no longer isolated units. Their interaction extends to everything that affects or is affected by the global variable. Thus it makes larger programs harder to understand.
By avoiding mutating globals, in the long run your code will be easier to understand, test and maintain.
Put a global statement at the top of your function and you should be good:
def onLoadFinished(result):
global feed
...
To demonstrate what I mean, look at this little test:
x = 0
def t():
x += 1
t()
this blows up with your exact same error where as:
x = 0
def t():
global x
x += 1
t()
does not.
The reason for this is that, inside t, Python thinks that x is a local variable. Furthermore, unless you explicitly tell it that x is global, it will try to use a local variable named x in x += 1. But, since there is no x defined in the local scope of t, it throws an error.
As the Python interpreter reads the definition of a function (or, I think, even a block of indented code), all variables that are assigned to inside the function are added to the locals for that function. If a local does not have a definition before an assignment, the Python interpreter does not know what to do, so it throws this error.
The solution here is to add
global feed
to your function (usually near the top) to indicate to the interpreter that the feed variable is not local to this function.
in my case that exact same error was triggered by a typo !
I thought my my var name was
varAlpha
but in the code i had defined
varalpha
& got the error
UnboundLocalError: local variable 'varAlpha' referenced before assignment
when calling varAlpha
I hope it helps somebody one day searching for that error & wondering (as my search for that error led me here while being unrelated with the use of global or not global which was a head scratcher !)
You can do like this for the function scope
def main()
self.x = 0
def incr():
self.x += 1
for i in range(5):
incr()
print(self.x)
This question already has answers here:
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 6 months ago.
I am using the PyQt library to take a screenshot of a webpage, then reading through a CSV file of different URLs. I am keeping a variable feed that incremements everytime a URL is processed and therefore should increment to the number of URLs.
Here's code:
webpage = QWebPage()
fo = open("C:/Users/Romi/Desktop/result1.txt", "w")
feed = 0
def onLoadFinished(result):
#fo.write( column1[feed])#, column2[feed], urls[feed])
#feed = 0
if not result:
print "Request failed"
fo.write(column1[feed])
fo.write(',')
fo.write(column2[feed])
fo.write(',')
#fo.write(urls[feed])
fo.write(',')
fo.write('404,image not created\n')
feed = feed + 1
sys.exit(1)
save_page(webpage, outputs.pop(0)) # pop output name from list and save
if urls:
url = urls.pop(0) # pop next url to fetch from list
webpage.mainFrame().load(QUrl(url))
fo.write(column1[feed])#,column2[feed],urls[feed],'200','image created','/n')
fo.write(',')
fo.write(column2[feed])
fo.write(',')
#fo.write(urls[feed])
fo.write(',')
fo.write('200,image created\n')
feed = feed + 1
else:
app.quit() # exit after last url
webpage.connect(webpage, SIGNAL("loadFinished(bool)"), onLoadFinished)
webpage.mainFrame().load(QUrl(urls.pop(0)))
#fo.close()
sys.exit(app.exec_())
It gives me the error:
local variable feed referenced before the assignment at fo.write(column1[feed])#,column2[feed],urls[feed],'200','image created','/n')
Any idea why?
When Python parses the body of a function definition and encounters an assignment such as
feed = ...
Python interprets feed as a local variable by default. If you do not wish for it to be a local variable, you must put
global feed
in the function definition. The global statement does not have to be at the beginning of the function definition, but that is where it is usually placed. Wherever it is placed, the global declaration makes feed a global variable everywhere in the function.
Without the global statement, since feed is taken to be a local variable, when Python executes
feed = feed + 1,
Python evaluates the right-hand side first and tries to look up the value of feed. The first time through it finds feed is undefined. Hence the error.
The shortest way to patch up the code is to add global feed to the beginning of onLoadFinished. The nicer way is to use a class:
class Page(object):
def __init__(self):
self.feed = 0
def onLoadFinished(self, result):
...
self.feed += 1
The problem with having functions which mutate global variables is that it makes it harder to grok your code. Functions are no longer isolated units. Their interaction extends to everything that affects or is affected by the global variable. Thus it makes larger programs harder to understand.
By avoiding mutating globals, in the long run your code will be easier to understand, test and maintain.
Put a global statement at the top of your function and you should be good:
def onLoadFinished(result):
global feed
...
To demonstrate what I mean, look at this little test:
x = 0
def t():
x += 1
t()
this blows up with your exact same error where as:
x = 0
def t():
global x
x += 1
t()
does not.
The reason for this is that, inside t, Python thinks that x is a local variable. Furthermore, unless you explicitly tell it that x is global, it will try to use a local variable named x in x += 1. But, since there is no x defined in the local scope of t, it throws an error.
As the Python interpreter reads the definition of a function (or, I think, even a block of indented code), all variables that are assigned to inside the function are added to the locals for that function. If a local does not have a definition before an assignment, the Python interpreter does not know what to do, so it throws this error.
The solution here is to add
global feed
to your function (usually near the top) to indicate to the interpreter that the feed variable is not local to this function.
in my case that exact same error was triggered by a typo !
I thought my my var name was
varAlpha
but in the code i had defined
varalpha
& got the error
UnboundLocalError: local variable 'varAlpha' referenced before assignment
when calling varAlpha
I hope it helps somebody one day searching for that error & wondering (as my search for that error led me here while being unrelated with the use of global or not global which was a head scratcher !)
You can do like this for the function scope
def main()
self.x = 0
def incr():
self.x += 1
for i in range(5):
incr()
print(self.x)
I have a program in python. part of the program is:
suggestengines = get_suggestengines(suggestengines)
sleeptimer = sleepcount * len(suggestengines)
seeds = get_seeds(dummydata=False)
For further programming I want to make a function of it:
def first_step():
suggestengines = get_suggestengines(suggestengines)
sleeptimer = sleepcount * len(suggestengines)
seeds = get_seeds(dummydata=False)
Now I get an error for "suggestengines" that I want to pass into get_suggestengines(). Also sleep timer and seeds get a marker, that I don't use them in the rest of the program. I googled it and got the answer: Us global. So I added global for everything
def first_step():
global suggestengines
global sleeptimer
global seeds
suggestengines = get_suggestengines(suggestengines) #which engines to run?
sleeptimer = sleepcount * len(suggestengines)
seeds = get_seeds(dummydata=False)
In further part of the program I have
for seed in tqdm(seeds, leave=True):
there the program gives me an error vor seeds in tqdm. If I change it to also make a def of it like:
def partTwo():
for seed in tqdm(seeds, leave=True):
Then I don't get an error anymore although I didn't used global. Can someone explain me why and if I need to use global in part 2 also?
The statement
global <identifier>
tells python that <identifier> should refer to a global when used in assignments. This is necessary in functions that change globals because Python has no syntactical difference between declaring a variable and assigning to an existing variable. The default in python is to have assignments in functions create new variables, rather than change global state.
When you just read from a variable there is no syntactic ambiguity, so Python will just use whatever variable it finds (i.e. global if there is no local one).
Example:
a = 1
def foo():
a = 2 # this will create a new, local variable a
def bar():
global a # "when I refer to a, I mean the global one"
a = 2 # this will change the global variable a
If no global with the specified name exists, the global statement itself will not create a new global variable, but any following assignment will. E.g. given the following:
def x():
global c
def y():
global c
c = 1
def z()
print c
x(); z() would be an error(global name 'c' is not defined), while y(); z() would print 1.
seeds hasn't been initialized yet by the time the for loop is hit, since its initialization is part of a def that hasn't been called yet. If you put the for loop inside a def then it will be called in the order you call the functions, so the interpreter won't complain until you actually use it.
The only thing to keep in mind here is this: use variables after they have been initialized.
Ok, I started coding this:
lastentry = 'first'
campdata = {'a1'=0,
'b2'=0}
class Someclass:
def on_window1_destroy(self, widget, data=None):
print campdata
def func1(self)
lastentry = 'b2'
def func2(self)
lastentry = 'a1'
def func2(self)
campdata[lastcall] +=1
But then I found out that python strings (and integers) were immutable...
So how do I get around ths?
I guess your problem is that you want to change the value of the global variable lastentry by calling func1 or func2, which doesn't work. The reason it does not work is because the variable is in the global scope, and assigning to the same name inside of a function just creates a local variable with the same name as the global one. To assign to a global variable, you need to declare it as such:
lastentry = "something"
def func1():
global lastentry #tell python to treat references to lastentry as global
lastentry = "somethingelse"
Note that you don't need to do this if all you are doing with the global value is reading it like in your third function. But if you assign to a variable, it is treated as local to its scope - which is normally the surrounding function - if you don't explicitly declare it global (or nonlocal in python3).
Global variables should only be used when neccessary as they add complexity to the code. In your case you can probably refactor your code to use an instance variable or class variable for lastentry instead of a global one.
Like others have said, there doesn't seem to be any attempt to modify a string in your code, so that's hardly the problem.
That said, lastcall looks random, should it perhaps be lastentry?
I don't see any problem with your code (except for some details). String immutability does not seem to be a problem, here.
You may want to write, instead of the code in your question:
campdata = {'a1': 0, # Not "= 0"
'b2': 0}
and
campdata[lastentry] +=1 # not "lastcall"
Also, as l4mpi mentioned, you need a global lastentry in the methods where it is modified.
Another point: relying on global variables is quite unusual. If at all possible, it would be best to use instance attributes (self.campdata, self.lastentry).