Why is it local, being that I am using global? [duplicate] - python

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)

Related

How can I refer to variable as global in python

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.

Change a variable inside from a if statement so the stament isnt true Python [duplicate]

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)

Are variables declared inside "with" statement local?

I was reading a question in StackOverflow where the user applied the "with" statement twice in a row, pipelining the results from a variable declared inside the first with statement into the second. Like so (simple example):
with open('first_file.txt', 'r') as f:
loaded_file = f.readlines()
#...Prepare a csv file somehow - loaded_file is not declared outside with...
with open("second_file.csv", "w") as f:
for line in loaded_file:
f.write(line+"\n")
Considering variable scopes, why does it work?
Only one statement creates a new scope: the def statement. Any other assignment creates a name that is local to the current function body.
The exceptions are:
A name declared global refers to the (module) global scope rather than the local function body.
A name declared nonlocal refers to the name defined in the closest containing function scope (or global scope if no other name is found)
The Python interpreter itself can define names.
In your example, f is either a local variable or a global, depending on the scope where the with statement occurs. In no way is f local to any other particular statement.
No, "with" statements does not create a new scope.
The "With" statement is a resource developed by the Python Dev team to generalize a common (and heavily recommended) practice of closing opened resources even after an exception ocurred. Imagine the following situation:
try:
f = open('file.txt', 'w')
#Do some processing that can raise exceptions and leave 'f' open, eventually locking the file or having trash data loaded into RAM.
#To avoid this situation, a mindful developer will do the following:
finally:
f.close()
It gets verbose easily.
To solve the problem, python dev team proposed the use of some dunder methods which encapsule this process: __enter__() and __exit__() - these are invoked "under the hood" when you use a "with" statement.
You can even implement them in your own classes!
class controlled_execution:
def __enter__(self):
set things up
return thing
def __exit__(self, type, value, traceback):
tear things down
with controlled_execution() as thing:
some code
In the end, a with statement, even though there's identation, is not a separate block of code. It is just an ellegant try...finaly block. It abstracts a "contained" piece of code.
This can be easily comprehended by looking at a try...except statement with variables declared inside the try:
x = 10
try:
y = load_using_failable_function()
z = 5
except FunctionFailureException:
y = 10
#If you treat it properly, there's nothing wrong with doing:
x = x + y + z
I hope it is clear to anyone else looking for this reason.
Consulted websites:
https://www.geeksforgeeks.org/with-statement-in-python/
https://effbot.org/zone/python-with-statement.htm

How can I change a global variable from within a function? [duplicate]

This question already has answers here:
Using global variables in a function
(25 answers)
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 7 months ago.
I'm trying to add or subtract from a defined variable, but how can I overwrite the old value with the new one?
a = 15
def test():
a = a + 10
print(a)
test()
Error message:
Traceback (most recent call last):
File "test.py", line 7, in <module>
test()
File "test.py", line 4, in test
a = a +10
UnboundLocalError: local variable 'a' referenced before assignment
The error that you get when you try to run your code is:
UnboundLocalError: local variable 'a' referenced before assignment
… which, on the face of it, seems strange: after all, the first statement in the code above (a = 15) is an assignment. So, what's going on?
Actually, there are two distinct things happening, and neither of them are obvious unless you already know about them.
First of all, you actually have two different variables:
The a in your first line is a global variable (so called because it exists in the global scope, outside of any function definitions).
The a in the other lines is a local variable, meaning that it only exists inside your test() function.
These two variables are completely unrelated to each other, even though they have the same name.
A variable is local to a function if there's a statement assigning to it inside that function - for instance, your a = a +10 line.
Even so, the error still looks strange - after all, the very first thing you do inside test() is assign to a, so how can it be referenced beforehand?
The answer is that, in an assignment statement, Python evaluates everything on the right hand side of the = sign before assigning it to the name on the left hand side – so even though the assignment is written first in your code, a gets referenced first in that right hand side: a +10.
There are two ways you can get around this. The first is to tell Python that you really want the a inside test() to be the same a in the global scope:
def test():
global a
a = a + 10
print(a)
This will work, but it's a pretty bad way to write programs. Altering global variables inside functions gets hard to manage really quickly, because you usually have lots of functions, and none of them can ever be sure that another one isn't messing with the global variable in some way they aren't expecting.
A better way is to pass variables as arguments to functions, like this:
a = 15
def test(x):
x = x + 10
print(x)
test(a)
Notice that the name doesn't have to be the same - your new definition of test() just says that it accepts a value, and then does something with it. You can pass in anything you like – it could be a, or the number 7, or something else. In fact, your code will always be easier to understand if you try to avoid having variables with the same name in different scopes.
If you play with the code above, you'll notice something interesting:
>>> a = 15
>>> test(a)
25
>>> a
15
… a didn't change! That's because although you passed it into test() and it got assigned to x, it was then x that got changed, leaving the original a alone.
If you want to actually change a, you need to return your modified x from the function, and then reassign it back to a on the outside:
>>> a = 15
>>>
>>> def test(x):
... x = x + 10
... print(x)
... return x
...
>>> a = test(a)
25
>>> a
25
You're modifying a variable a created in the scope of the function test(). If you want the outer a to be modified, you could do:
a = 15
def test():
global a
a = a + 1
print(a)
test()
I would do it this way:
def test(a):
a = a +10
return a
print(test(15))
Note that in the version hereby proposed there are some things differing from yours.
First, what I wrote down would create a function that has, as an input, the value a (in this case set to 15 when we call the function -already defined in the last line-), then assigns to the object a the value a (which was 15) plus 10, then returns a (which has been modified and now is 25) and, finally, prints a out thanks to the last line of code:
print(test(15))
Note that what you did wasn't actually a pure function, so to speak. Usually we want functions to get an input value (or several) and return an input value (or several). In your case you had an input value that was actually empty and no output value (as you didn't use return). Besides, you tried to write this input a outside the function (which, when you called it by saying test(a) the value a was not loaded an gave you the error -i.e. in the eyes of the computer it was "empty").
Furthermore, I would encourage you to get used to writing return within the function and then using a print when you call it (just like I wrote in the last coding line: print(test(15))) instead of using it inside the function. It is better to use print only when you call the function and want to see what the function is actually doing.
At least, this is the way they showed me in basic programming lessons. This can be justified as follows: if you are using the return within the function, the function will give you a value that can be later used in other functions (i.e. the function returns something you can work with). Otherwise, you would only get a number displayed on screen with a print, but the computer could not further work with it.
P.S. You could do the same doing this:
def test(a):
a +=10
return a
print(test(15))
a = 15
def test():
global a
a = a + 10
print(a)
test()
If you want to change the values of local variables inside a function you need to use the global keyword.
The scope of the variable is local to the block unless defined explicitly using keyword global. There is another way to access the global variable local to a function using the globals function:
a = 15
def test():
a = globals()['a']
a += 10
print(a)
test()
The above example will print 25 while keeping the global value intact, i.e., 15.
The issue here is scope.
The error basically means you're using the variable a, but it doesn't exist yet. Why? The variable a has not been declared in the test() function. You need to "invite" global variables before using them.
There are several ways to include a variable in the scope of a function. One way is to use it as a parameter like this:
def test(number):
number = number + 10
print(number)
Then implement it as:
test(a)
Alternatively, you could also use the global keyword to show the function that a is a global variable. How? Like this:
def test():
global a
a = a + 10
print(a)
Using the global keyword just tells the test where to look for a.
With the first method, you can't modify the global variable a, because you made a copy of it and you're using the copy. In the second method, though, any changes you make in the function test() to a, will affect the global variable a.
# All the mumbo jumbo aside, here is an experiment
# to illustrate why this is something useful
# in the language of Python:
a = 15 # This could be read-only, should check docs
def test_1():
b = a + 10 # It is perfectly ok to use 'a'
print(b)
def test_2():
a = a + 10 # Refrain from attempting to change 'a'
print(a)
test_1() # No error
test_2() # UnboundLocalError: ...
Your error has nothing to do with it being already defined…
A variable is only valid inside its so-called scope: If you create a variable in a function it is only defined in this function.
def test():
x = 17
print(x) # Returns 17
test()
print(x) # Results in an error.

Python: Understanding global a little bit more

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.

Categories

Resources