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

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

Related

Is there a way to change a variable within a function if the variable is being passed as an argument?

If I had the code:
num = 3
def add(variable, number):
variable += number
add(num, 2)
print(num)
It would output 3 because inside the function, the temporary variable variable inside the function is being added to instead of the num variable. Is there a way to make it so when I pass num as the first argument, 3 would be added to num instead of variable and num would be changed to 5?
When you call a function with arguments, you pass the arguments value to the function. That function has no connection to the original variable and it cannot be reassigned to a new value.
The correct way to accomplish your goal here is to return a new value:
num = 3
def add(variable, number):
return variable + number
num = add(num, 2)
print(num)
You could write it like this:
num = 3
def add(n1, n2):
return n1 + n2
print(add(num, 2))
The original assignment is not going to update when printing num.
I think you need to explicitly assign the new value to the num variable. For example, you could do:
num = 3
def add(variable, number)
return variable + number
num = add(num, 2)
print(num) #Prints out 5
Your question touches on one of the more esotheric and easy to misunderstand features of Python: mutables and immutables.
Here is the official documentation on mutable and immutable sequence types;
https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types
https://docs.python.org/3/library/stdtypes.html#immutable-sequence-types
As you can tell, only sequences and complex objects are mutable, and thus may be altered by the function.
Base types like integers and floats cannot be changes within the function as you describe, though strings can, as they count as sequences.
In your example, you're using an integer - so this will not work. However, with a string, array, dictionary or complex object (a class of your own design), this _will work.
If you're coming at it from another programming language like C++, think of mutables like references, and immutables like values. If you pass a value, any changes to the object referenced within the scope of the function do not live past the life of the function scope. Any changes to objects with references on them, however, do persist.
This post does an excellent job of explaining this in much more depth, and I would highly recommend skimming it;
https://medium.com/#meghamohan/mutable-and-immutable-side-of-python-c2145cf72747
The purpose of the add function is to add two numbers together which will result in a number. This is something completely different than doing operations on already existing variables. If you want to use variables both inside and outside function, you can use the keyword 'global'. This lets the function know that this is a globally defined variable and you will be able to do operations on it. So you can for example do:
num = 3
def add(number):
global num
num += number
add(2)
print(num)
Which will print 5
If you just want a function to add two numbers and assign this result to the already globally defined variable, you can use:
num = 3
def add(variable, number):
return variable + number
num = add(num, 2)
print(num)
This will also print 5

Using the value of an if parameter without saving it into a variable

Is it possible to "re-use" the value of a parameter of an if-clause?
I have a function that returns either True or a dictionary:
def foo():
if random.randint(0, 1) == 0:
return True
else:
return {"time": time.time()}
If foo() returns the dictionary, I also want to return it. If foo() returns True I want to just continue.
Currently I'm using:
if_value = foo()
if if_value is not True:
return if_value
My goal would be to avoid saving the return value of the function into a variable, because it makes my code really ugly (I need to do this about 20 times in a row).
When using a Python shell, it seems to work like this:
if function_that_returns_True_or_an_int() is not True:
return _
Any suggestions about this?
You can use the walrus operator (:=) to declare a variable and assign to it, then do your comparison
if (x := your_function()) == condition:
# something
else:
# something else
print(x) # x is still a named variable and in scope

Python while loop UnboundLocalError

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()

Using a variable in a function in another function in python

I returned the variable and I still get the variable is still undefined. Can someone help?
def vote_percentage(s):
'''(string) = (float)
count the number of substrings 'yes' in
the string results and the number of substrings 'no' in the string
results, and it should return the percentage of "yes"
Precondition: String only contains yes, no, and abstained'''
s = s.lower()
s = s.strip()
yes = int(s.count("yes"))
no = int(s.count("no"))
percentage = yes / (no + yes)
return percentage
def vote(s):
##Calling function
vote_percentage(s)
if percentage == 1.0: ##problem runs here
print("The proposal passes unanimously.")
elif percentage >= (2/3) and percentage < 1.0:
print("The proposal passes with super majority.")
elif percentage < (2/3) and percentage >= .5:
print("The proposal passes with simple majority.")
else:
print("The proposal fails.")
Based on how you are implementing your code, if you define a variable in one method, you cannot access it in another.
The percentage variable inside vote_percentage is within scope of the vote_percentage method only, which means it cannot be used outside that method the way you are trying to use it.
So, in your vote_percentage you are returning percentage. Which means, that when you call this method, you need to actually assign its result to a variable.
So, to show you with an example using your code.
Looking at your code from here:
def vote(s):
##Calling function
vote_percentage(s)
What you need to be doing when calling vote_percentage is actually store the return value, so you can do something like this:
percentage = vote_percentage(s)
Now, you actually have the return of vote_percentage in the variable percentage.
Here is another small example to further explain scoping for you:
If you do this:
def foo()
x = "hello"
If you are outside the method foo(), you cannot access the variable x. It is within the "scope" of foo only. So if you do this:
def foo():
x = "hello"
return x
And you have another method that needs the result of foo(), you do not have access to that "x", so you need to store that return in a variable like this:
def boo():
x = foo()
As you can see in my example, similar to your code, I even used the variable x in boo(), because it is a "different" x. It is not within the same scope as foo().

Accessing global function's variables in a local function

Here's my test script:
def main(): #global
n = 1
z = None
def addone(): #local
if not z:
n = n+1
addone()
print n
main()
I step into the addone() function once it hits the calling line.
At this point I can only see the variable z, but cannot see n.
Now, if n is referenced before assignment, shouldn't z be too?
Similarly, if I change n=n+1 to z='hi', I can no longer see z!
This is contrary to all my previous beliefs about local/global functions! The more you know, the more you know you don't know about Python.
Question(s):
Why can I see one but not the other?
Do I want to be prepending global to these variables I want to reassign?
The best solution is to upgrade to Python 3 and use in the inner function nonlocal n. The second-best, if you absolutely have to stick with Python 2:
def main(): #global
n = [1]
z = None
def addone(): #local
if not z:
n[0] += 1
addone()
print n[0]
main()
As usual, "there is no problem in computer science that cannot be solved with an extra level of indirection". By making n a list (and always using and assigning n[0]) you are in a sense introducing exactly that life-saving "extra level of indirection".
Okay, after some testing, I realised that it all has to do with the reassignment of variables.
for example:
def main(): #global
n = 1
z = None
def addone(): #local
if not z:
x = n+1
addone()
print n
main()
Now shows both n and z when I am inside the addone() function. This is because I am no longer trying to reassign n, makes sense to me so as to protect global variables from manipulation if one so happens to use similar names in local functions.

Categories

Resources