Why is this variable considered local? - python

I have this code:
with open("01-1-input.txt", "r") as f:
inputs = [int(i[:-2] if i[-1] == "n" else i) for i in f.readlines()]
total_mass = 0
def calculate_fuel_for_mass(mass):
fuel_for_mass = mass // 3 - 2
if fuel_for_mass > 0:
total_mass += fuel_for_mass
calculate_fuel_for_mass(fuel_for_mass)
else:
return 0
for i in inputs:
calculate_fuel_for_mass(i)
print(total_mass)
And it's throwing an UnboundLocalError: local variable 'total_mass' referenced before assignment.
Why is that? I thought any variable declared in the main scope is global?

The line
total_mass += fuel_for_mass
can be thought of as equivalent to
total_mass = total_mass + fuel_for_mass
Given a setup like this, python sees an assignment happening to a variable in local scope (inside the function).
A minimal demonstration of this behaviour can be seen as follows:
var = 42
def f():
var = var + 1
# var += 1 would also show the same behaviour
f() #UnboundLocalError: local variable 'var' referenced before assignment
Python infers that there is a local variable total_mass because it sees an assignment to the variable in the local scope.
However, the local variable total_mass has not been assigned a value,
and so you see the error as shown.
You can use the global keyword before the assignment to access the variable in the global scope as follows
var = 42
def f():
global var
var = var + 1
f() #var is now 43 in global scope

At the beginning of your function, put
global total_mass

For this, you have to know how variable scopes and mutable/immutable types in Python work. The int type is immutable, so when you try to "modify" it in the function, you essentially create a new variable with local scope. As the compiler can see that the variable is going to be local to the function, it assumes that you want to access the local variable in the first place, rather than the global one. It is possible to declare the variable global using the global keyword, however it's considered bad practice, as the program becomes harder to read and to debug.

Related

Im getting the referenced before assignment error

I am making a system that reads a file, moves it to a new file, and moves it back with a new variable at the end of each line.
It is saying that linesRead is referenced before assignment
import random
handVar = 0
handList = []
linesRead = 'test'
def dealCards(numPlayers, cardList):
random.shuffle(cardList)
for i in range(0, numPlayers):
poppedCard1=cardList.pop()
poppedCard2=cardList.pop()
hand = (poppedCard1 + ', ' + poppedCard2)
handList.append(hand)
cardFile = open('players.txt', 'r')
playerLines= cardFile.readlines()
cardFile.close()
for i in playerLines:
for f in i:
linesRead = linesRead + f
print(linesRead)
tempFile = open('tempFile.txt', 'w')
tempFile.write(playerLines)
tempFile.close
tempFile = open('tempFile.txt', 'r')
playerFile = open('players.txt', 'a')
for i in tempFile:
newLine= (i + ', ' + handList[handVar] + ', ' + handList[handVar+1])
playerFile.write(newLine)
handVar = handVar + 2
The reason for the error scopes of the variables.
You are defining the variable linesRead in the global scope (outside of the function). It is available inside the function as long as you do not try to reassign the variable. When you reassign, Python treats is as a local scope variable (the scope of the function), and since you are using it in the reassignment, it is not able to find the assignment of that var in local scope.
Let's look at the following examples:
num = 42
def foo():
print(num)
foo()
Output:
42
In this case num is a variable defined in the Global scope (aka. module scope). It is defined at the top level of the module and is available in the local scopes of functions.
But the things are different in the following example:
num = 42
def foo():
print(num)
num = 12
foo()
Output:
UnboundLocalError: local variable 'num' referenced before assignment
What happens in this case is Python making the num a variable of the local scope of the foo function. That is it has nothing to do with the num of the global scope. Since I'm trying to print it before I assign it a value, it gives me an error.
Things are different when I move the assignment above of the print function call:
num = 42
def foo():
num = 12
print(num)
foo()
Output:
12
Same happens in this case, but since num is already assigned in the local scope by the time I'm calling the print, it won't error.
Solution
One of the solutions is to include the var as a global in the function. Something like this
def dealCards(numPlayers, cardList):
global linesRead
it will make the var from global variable available at the local scope.
But in this case if you modify the var in the function, the one at the module level will be changed as well
num = 42
def foo():
global num
print(num)
num = 12
foo()
print(num)
Output
42
12
Here is a fine, detailed read on Python scopes:
https://realpython.com/python-scope-legb-rule/

global variable error in Python

I am learning Python on my own and I am baffled on what is wrong in the following code
glob_var = 0
def print_glob_var():
s = 0
while glob_var > 0:
s = s+1
glob_var = glob_var - 1
return s
#print (globvar)
def main():
global glob_var
glob_var = 4
print_glob_var()
main()
I am getting error "UnboundLocalError: local variable 'glob_var' referenced before assignment" . However when I use only the print the code block works fine.
What I am doing wrong. I am using Python 3.5.2
In order to change the value of a global variable inside a function, you must declare it global inside the function. You seem to do so in function main, but not in function print_glob_var.
Python analyses the body of print_glob_var, sees an assignment to glob_var (specifically glob_var = glob_var - 1) and no global statement, and decides based on that that glob_var is a local variable that it expects to see defined within the function. If you remove the assignment you will no longer get this error, although of course that creates new problems. Alternatively you could add global glob_var to the function. Including it in main is not enough, you need that statement everywhere the variable is used.
This is the kind of reason that using non-constant global variables in Python is a bad idea. Learn about classes.
glob_var = 4
def print_glob_var():
global glob_var # Set glob_var as global
s = 0
while glob_var > 0:
s = s+1 # You can do s += 1 here
glob_var = glob_var - 1
print(glob_var) # Your commented out print() was after the return statement
return s # so it would never be reached.
def main():
print_glob_var()
main()

Python: why global variable act as local variable in method? [duplicate]

How do global variables work in Python? I know global variables are evil, I'm just experimenting.
This does not work in python:
G = None
def foo():
if G is None:
G = 1
foo()
I get an error:
UnboundLocalError: local variable 'G' referenced before assignment
What am I doing wrong?
You need the global statement:
def foo():
global G
if G is None:
G = 1
In Python, variables that you assign to become local variables by default. You need to use global to declare them as global variables. On the other hand, variables that you refer to but do not assign to do not automatically become local variables. These variables refer to the closest variable in an enclosing scope.
Python 3.x introduces the nonlocal statement which is analogous to global, but binds the variable to its nearest enclosing scope. For example:
def foo():
x = 5
def bar():
nonlocal x
x = x * 2
bar()
return x
This function returns 10 when called.
You need to declare G as global, but as for why: whenever you refer to a variable inside a function, if you set the variable anywhere in that function, Python assumes that it's a local variable. So if a local variable by that name doesn't exist at that point in the code, you'll get the UnboundLocalError. If you actually meant to refer to a global variable, as in your question, you need the global keyword to tell Python that's what you meant.
If you don't assign to the variable anywhere in the function, but only access its value, Python will use the global variable by that name if one exists. So you could do:
G = None
def foo():
if G is None:
print G
foo()
This code prints None and does not throw the UnboundLocalError.
You still have to declare G as global, from within that function:
G = None
def foo():
global G
if G is None:
G = 1
foo()
print G
which simply outputs
1
Define G as global in the function like this:
#!/usr/bin/python
G = None;
def foo():
global G
if G is None:
G = 1;
print G;
foo();
The above python prints 1.
Using global variables like this is bad practice because: http://c2.com/cgi/wiki?GlobalVariablesAreBad

Using a variable defined outside a function in a def() statment

I am working on a python thing and I assigned variable x*y to SecureNum. I then define a function in which I write: while R*S != SecureNum: it spits up the error that I am referencing SecureNum before assignment, even though it has been assignment earlier but not in the function. How can I fix this?
Thanks in advance!
George
Probably you are trying to assign to SecureNum later in that function
Because you haven't declared SecureNum to be global and Python sees you are assigning to it, it forces it to be a local variable.
SecureNum = 12345
def f(R, S):
if R * S != SecureNum: #<== local SecureNum shadows the global one
...
...
SecureNum = ... #<= This means SecureNum is a local
def g(R, S):
global SecureNum
if R * S != SecureNum: #<== now this is the global SecureNum
...
...
SecureNum = ... #<= and so is this one
This can be surprising because the problem isn't because really at the line where you are testing the value, it's because you are trying to rebind the name further down.
Use the following at the beginning of your function:
global SecureNum

Python global/local variables

Why does this code work:
var = 0
def func(num):
print num
var = 1
if num != 0:
func(num-1)
func(10)
but this one gives a "local variable 'var' referenced before assignment" error:
var = 0
def func(num):
print num
var = var
if num != 0:
func(num-1)
func(10)
Because in the first code, you have created a local variable var and used its value, whereas in the 2nd code, you are using the local variable var, without defining it.
So, if you want to make your 2nd function work, you need to declare : -
global var
in the function before using var.
def func(num):
print num
var = 1 <-- # You create a local variable
if num != 0:
func(num-1)
Whereas in this code:
def func(num):
print num
var = var <--- # You are using the local variable on RHS without defining it
if num != 0:
func(num-1)
UPDATE: -
However, as per #Tim's comment, you should not use a global variable inside your functions. Rather deifine your variable before using it, to use it in local scope. Generally, you should try to limit the scope of your variables to local, and even in local namespace limit the scope of local variables, because that way your code will be easier to understand.
The more you increase the scope of your variables, the more are the chances of getting it used by the outside source, where it is not needed to be used.
If you have var = ... anywhere in a function, the name "var" will be treated as a local variable for the entire function, regardless of where that assignment occurs. This means that all occurrences of var in your function will be resolved in the local scope, so the right hand side of var = var results in the referenced before assignment error because var has not yet been initialized in the function's scope.
You can read a global without declaring it global. But to write a global, you need to declare it global.
In your second piece of code you have created a local variable in RHS and without defining it, you are assigning it to the LHS variable var which is global (a variable defined outside the function is considered global explicitly).
If your intention is to create a local variable inside the function and assign it to the value of the global variable, this will do the trick:
var = 0
def func(num):
print num
func.var = var # func.var is referring the local
# variable var inside the function func
if num != 0:
func(num-1)
func(10)
def runscan(self):
p = os.popen('LD_PRELOAD=/usr/libv4l/v4l1compat.so zbarcam
/dev/video0','r')
def input(self):
self.entryc.insert(END, code)
how about this?
i want use local 'code' to the next function to insert the result of barcode to my Tkinter entryBox..
Thanks
Each function block is a local scope. If you want to assign to global variables, you need to do so explicitly:
var = 0
def func(num):
print num
global var
var = 1
if num != 0:
func(num-1)
print var # 0
func(2)
print var # 1

Categories