Python while loop UnboundLocalError - python

I need a function with a while loop, that as long as the condition is False calls the function again.
This code will obviously result in a endless loop since "i" is always re declared as "0":
def fun():
i = 0
# does something else
while i < 5:
i += 1
fun()
print('done')
fun()
So I see no other way than to go about it like this:
i = 0
def fun():
# does something else
while i < 5:
i += 1
fun()
print('done')
fun()
But with this code It says local variable 'i' referenced before assignment.
I don't get it what am I doing wrong here?
I know I could use an if statement here, but that would be much more complicated and can get in my way in the project, although its not impossible.

Basically, the value i has not been declared in the function, so the function doesn't know what i is. There are a couple of ways to fix this.
One way is to put the while loop OUTSIDE of the function. This is how it would look like:
i = 0
def fun():
#Do Something...
print('done')
while i < 5:
i += 1
fun()
Another way would be to add the parameter i into the function. You do this by adding i into the brackets. This is how it would look like:
i = 0
def fun(i): #I Added An i Here So That The Function Knows We Need A Value Of i
#Do Something...
while i < 5:
i += 1
fun(i) #I Use The Same Value Of i Set At The Beginning
print('done')
fun(i) #I Call The Function Again
You could also set i as a global variable, meaning it can be used in the function too. To do that, just add global and the variable. This is how I did it:
i = 0
def fun():
global i
#Do Something...
while i < 5:
i += 1
fun()
print('done')
fun()
If neither of these 3 methods work, you could try and maybe use a for loop: something like for i in range(0, 5): , which would work too.

variable i is not in the scope of the function. Hence it is not accessible.
I believe the below code will help you get the desired output.
def fun(count):
# does something else
if(count >= 5):
return
fun(count + 1)
print('done')
fun(0)

Since other posts has offered remedy already, here I just point out the reason more detail:
This is one of the common gotchas to the new learners, the reason is that -
it's because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope.
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, it’s assumed to be a local unless explicitly declared as global.
It can be a surprise to get the UnboundLocalError in previously working code when it is modified by adding an assignment statement somewhere in the body of a function.

hope this is what you are looking for:
def fun(i=0):
# does something else
result = True
while result:
print(i)
i = i + 1
while i >= 5:
result = False
break
print('done')
fun()

Related

Why is this global value treated as a local value?(python)

I am writing a tic-tac-toe program and I noticed that the "turn" value must have "global" before it. However, it is already considered a global value. Why is it treated as a local value? Out of all the other projects I have done, I have never encountered this problem. Further, all the other variables I have declared are already considered global here.
Here is the code:
players = ["O", "X"]
buttons = [[0,0,0],
[0,0,0],
[0,0,0]]
def newGame():
turn = random.choice(players)
def nextTurn(row, column):
global turn
if buttons[row][column]['text'] == "" and check_win == False:
if turn == players[0]:
buttons[row][column]['text'] = turn
if check_win == False:
turn = players[1]
label.config(text=players[1] + " turn")
The problem seems to lie in the 'turn = players[1], but I do not know why.
Also, in a piece of sample code I experimented with, there was one instance that said the variable was not even defined, is it somehow connected to this problem? I have tried removing the global call, even in the sample code I learned from, where there were no nested functions, however, the same problem seems to occurs due to the line mentioned above. I have even tried making the variable an int or string, still the line mentioned above causes an error.
You don't need the global keyword to access the value of a global variable, but you do need global to assign a new definition to that global variable name.
Here's a simpler example to explain what's happening here.
x = 2
def test_1():
print(x)
def test_2():
x += 1
print(x)
def test_3():
global x
x+=1
print(x)
You should find that test_1() and test_3() can be used without any issues, but test_2() throws an error.
Note: this does not necessarily prevent us from modifying global variables without the global keyword. For example, the following code runs without any error.
x=[10]
def test():
x[0]+=1
print(x)
Also, in particular your context, you should really be using nonlocal rather than global because you are using nested functions. Consider the following.
x=10
def test():
x = 2
def test_1():
global x
x+=1
print(x)
def test_2():
nonlocal x
x+=1
print(x)
test_1()
Try running this script and changing the test_1() call at the end to test_2().

Local variable referenced before assginment (not making sense...)

So I wrote this fragment of code inside one of my projects, and defined n to be a boolean value True. Then, I used it to make a toggle case of a pause/resume button. For some reason, I get the error for using n in the if statement before allegedly assigning it inside the if and else code, although I already assigned it above the whole function.
Can somebody explain this error? And maybe suggest a way to fix it?
n = True
def pauseresume():
if n:
pauseb.configure(text="Resume")
n = False
else:
pauseb.configure(text="Pause")
n = True
You can not use global var in a function
solution:
def pauseresume():
global n
if n:
...
For detail, click
Using global variables in a function.
If you want to use a global variable, you need to explicitely use it via global keyword.
n = True
def pauseresume():
global n
pauseb.configure(text="Resume" if n else "Pause")
n = not n # switch to other bool value

Varialble re-initalized in multiple function calls

I have to execute the following code wherein I will be calling the function main again and again.
so here as I need to use i = i+1, I need to declare and initialize i in the first place right, but when i call the main function it again defines i=0 and the whole purpose of i = i+1 is lost.
How can I solve this error?
I have given the condition just as an example.
Basically what I want is i should be initialized only once, inspite of how many number of times main is called.
def main():
i = 0
if 0<1:
i = i+1
y = i
There are a couple ways to do this that don't involve globals. One is capture the value of i in a closure and return a new function that increments this. You will need to call the initial function once to get the returned function:
def main():
i = 0
def inner():
nonlocal i
i += 1
return i
return inner
f = main()
f()
# 1
f()
# 2
You can also create a generator which is a more pythonic way to do this. The generator can be iterated over (although use caution since it iterates forever) or you can get a single value by passing it to next():
def main():
i = 1
while True:
yield i
i += 1
f = main()
next(f)
# 1
next(f)
# 2
You can also use itertools.count
So you haven't declared i as a global variable
Do something like this
global i
i = 0
def main():
if 0<1:
global i
i = i+1
y = i
The reason behind this is because inside a function all the variables are local meaning they only exist inside the function while the function is called, so if you want a function to be able to change a variable for the whole code, you'll need to announce it as a global so python knows to change the value of it for the entire code
I'm not sure exactly what you are trying to do, but I believe there is an easier way to do whatever it is you are doing
It looks like you want to maintain state in a function call which is a good reason to convert it to a class.
class MyClass:
def __init__(self):
self.i = 0
def main(self):
self.i += 1
y = self.i
myclass = MyClass()
myclass.main()
myclass.main()
print(myclass.i)

Why can I edit object by calling their methods but not referencing their variable names from within a smaller scope

My main() function is:
def main():
...
def _help():
...
1 a += somelist
2 a.append(something)
a=[]
_help()
What's weird is that line 2 works perfectly fine, but line 1 throws an UnboundLocalError: Local variable 'a' referenced before assignment.
Even when I declare a as a global variable at the top of either main or _help, it still doesn't work. Why is this?
Both of these lines are editing the same variable which makes me think either both or neither of them should work. How do I get line 1 to work?
Whenever you use <variable> = <something> in Python, Python automatically assumes it is a local variable, unless specifically told otherwise.
For example:
a = 1
def f():
if False:
a = 0
print(a) # UnboundLocalError
f()
In this case, += works as assignment as well, but .append does not assign to a, but calls a method.
This is fixed by placing a nonlocal a in your function, so it can assign to the a outside of its scope:
def main():
...
def _help():
nonlocal a
a += somelist # Works!
But in this case, you can just do a.extend(somelist).

Alternate to global variable in Python

I am implementing a recursive function in which I need to remember a global value. I will decrement this value in every recursive call and want it to reflect in other recursive calls also.
Here's a way I've done it.
First way:
global a
a = 3
def foo():
global a
if a == 1:
print 1
return None
print a
a -= 1 # This new 'a' should be available in the next call to foo()
foo()
The output:
3
2
1
But I want to use another way because my professor says global variables are dangerous and one should avoid using them.
Also I am not simply passing the variable 'a' as argument because 'a' in my actual code is just to keep track of some numbers, that is to track the numbering of nodes I am visiting first to last. So, I don't want to make my program complex by introducing 'a' as argument in every call.
Please suggest me whatever is the best programming practice to solve the above problem.
Don't use a global; just make a a parameter to the function:
def foo(a):
print a
if a == 1:
return None
foo(a-1)
foo(3)
Try this :
Use a parameter instead of a global variable.
Example code
a = 3
def foo(param):
if param == 1:
print 1
return None
print param
foo(param - 1)
foo(a)

Categories

Resources