While-loop: UnboundLocalError: local variable referenced before assignment - python

I'm using python 3.5.
So I'm trying to create a function that takes x and y as positive float input, and then computes and returns R = x - N * y, where N is the largest integer, so that x > N * y.
I made this function:
def floatme(x,y):
N = 1
while x <= N * y:
R = x - N * y
N = N+1
return R
but then I receive the following error, when running my function:
UnboundLocalError: local variable 'R' referenced before assignment
I searched around and found that this happens when an assigned variable in the function, is already assigned outside of it. But this is not the case for my function, so I do not understand why Python is complaining?

R is defined inside the while loop. If the condition of the while loop is not true initially, its body never executes and R is never defined. Then it is an error to try to return R.
To solve the problem, initialize R to something before entering the loop.
If not entering the loop is an error condition, i.e. the caller should not be passing in values that cause the problem to begin with, then catch the UnboundLocalError using a try/except structure and raise a more appropriate exception (such as ValueError).

I'm afraid your code has an infinite loop with while x <= N * y: . Value of x will never increase in the code. (perhaps you meant to use >= instead?)
That being said, you will still get UnboundLocalError even if you define R outside. You have to tell the function that it's global.
R = None # init
def floatme(x,y):
global R # THIS IS THE KEY LINE
N = 1
while x >= N * y: # changed to >=
R = x - N * y
N = N+1
return R
At this point it's worth noting that this function is just doing x % y if x>=y else None so I'm not sure if I get the intent here.

Related

Montecarlo Pi Estimation code returning zero

Having trouble getting this code to work. Only ever prints 0.0. I'm a complete beginner to python and I'm aware that I've probably made a very simple mistake, and that my code is poorly written.
import math
import random as ran
import numpy as np
nodarts=1000
nhits = 0
def isInTheCircle(nhits,nodarts):
for i in range(nodarts):
x = ran.uniform(-1,1)
y = ran.uniform(-1,1)
if np.sqrt(x*x + y*y) >= 1:
nhits += 1
isInTheCircle(nhits,nodarts)
pi = (4.0*nhits)/(nodarts)
print(pi)
The value of nhits never changes from zero.
You have a function defined (isInTheCircle) and you call this function, but it does not return anything. You need to rewrite it to return nhits and assign this value to a variable (presumably also called nhits).
def isInTheCircle(nhits,nodarts):
for i in range(nodarts):
x = ran.uniform(-1,1)
y = ran.uniform(-1,1)
if np.sqrt(x*x + y*y) <= 1:
nhits += 1
return nhits
nhits = isInTheCircle(nhits,nodarts)
pi = (4.0*nhits)/(nodarts)
print(pi)
What may be confusing you is the "scope" of the variable nhits. Basically, just because you have a variable named nhits inside and outside the function does NOT make them the same variable. The variable inside the function changes, but the variable outside the function does not necessarily change (it does sometimes depending on type....but that's another story). Read up on "variable scope in python" to better understand this.

The solution always returns x=0

On using this code I get the value returned 0 always
def fi(arr,mini):
print(arr)
if(len(arr)<3):
x = mini
return
for j in range(1,(math.ceil(len(arr)/2) )):
l1 = 2*j+1
if(med(arr[0:l1])<mini):
mini= med(arr[0:l1])
print("hello", mini)
fi(arr[1:],mini)
return x
You define x only if len(arr) < 3. In other cases it is unassigned. You should add a default value before the if block, or within an else block depending on what you are trying to do.
You haven't declared x before assigning it to mini. What should your function return by default?
you define local variable 'x' whose scope is limited to if block and you are trying to return this variable from the function, so it's getting undefined. Better define local variable x in the function and give it some default value which should be return by the function.
def fi(arr,mini):
x = some_default_value
print(arr)
if(len(arr)<3):
x = mini
return
for j in range(1,(math.ceil(len(arr)/2) )):
l1 = 2*j+1
if(med(arr[0:l1])<mini):
mini= med(arr[0:l1])
print("hello", mini)
fi(arr[1:],mini)
return x

Why does the UnboundLocalError occur on the second variable of the flat comprehension?

I answered a question here: comprehension list in python2 works fine but i get an error in python3
OP's error was using the same variables for max range and indices:
x = 12
y = 10
z = 12
n = 100
ret_list = [ (x,y,z) for x in range(x+1) for y in range(y+1) for z in range(z+1) if x+y+z!=n ]
This is a Python-3 error only, and related to the scopes that were added to the comprehension to avoid the variables defined here "leaking". Changing the variable names fixes that.
The error is:
UnboundLocalError: local variable 'y' referenced before assignment
because outer, global y is shadowed by the local scope.
My question is: why do I get the error on y and not on z or x ?
EDIT: If I remove the loop on x, the error moves to z:
>> ret_list = [ (x,y,z) for y in range(y+1) for z in range(z+1) if x+y+z!=n ]
UnboundLocalError: local variable 'z' referenced before assignment
If I just do one loop:
ret_list = [ (x,y,z) for y in range(y+1) if x+y+z!=n ]
it works. So I'm suspecting that the first range function is evaluated before all the other expressions, which leaves the value of x intact. But the exact reason is still to be found. Using Python 3.4.3.
This behaviour is (implicitly) described in the reference documentation (emphasis mine).
However, aside from the iterable expression in the leftmost for clause, the comprehension is executed in a separate implicitly nested scope. This ensures that names assigned to in the target list don’t “leak” into the enclosing scope.
The iterable expression in the leftmost for clause is evaluated directly in the enclosing scope and then passed as an argument to the implictly [sic] nested scope. Subsequent for clauses and any filter condition in the leftmost for clause cannot be evaluated in the enclosing scope as they may depend on the values obtained from the leftmost iterable. For example: [x*y for x in range(10) for y in range(x, x+10)].
This means that:
list_ = [(x, y) for x in range(x) for y in range(y)]
equivalent to:
def f(iter_):
for x in iter_:
for y in range(y):
yield x, y
list_ = list(f(iter(range(x))))
As the name x in for the leftmost iterable is read in the enclosing scope as opposed to the nested scope then there is no name conflict between these two uses of x. The same is not true for y, which is why it is where the UnboundLocalError occurs.
As to why this happens: a list comprehension is more-or-less syntactic sugar for list(<generator expression>), so it's going to be using the same code path as a generator expression (or at least behave in the same way). Generator expressions evaluate the iterable expression in the leftmost for clause to make error handling when the generator expression somewhat saner. Consider the following code:
y = None # line 1
gen = (x + 1 for x in range(y + 1)) # line 2
item = next(gen) # line 3
y is clearly the wrong type and so the addition will raise a TypeError. By evaluating range(y + 1) immediately that type error is raised on line 2 rather than line 3. Thus, it is easier to diagnose where and why the problem occurred. Had it occurred on line 3 then you might mistakenly assume that it was the x + 1 statement that caused the error.
There is a bug report here that mentions this behaviour. It was resolved as "not a bug" for reason that it is desirable that list comprehensions and generator expressions have the same behaviour.

compile error when using outer defined variable from inner function in python [duplicate]

here is my code:
def f(x):
def g(n):
if n < 10:
x = x + 1
g(n + 1)
g(0)
When I evaluate f(0), there would be an error "x referenced before assignment".
However, when I use "print x" instead of "x = x + 1" , it will work.
It seems that in the scope of g, I can only use x as an "use occurrence" but not a "binding occurrence". I guess the problem is that f passes to g only the VALUE of x.
Am I understanding it correctly or not? If not, can someone explain why the left side of "x = x + 1" is not defined before reference?
Thanks
You are understanding it correctly. You cannot use x to assign to in a nested scope in Python 2.
In Python 3, you can still use it as a binding occurrence by marking the variable as nonlocal; this is a keyword introduced for just this usecase:
def f(x):
def g(n):
nonlocal x
if n < 10:
x = x + 1
g(n + 1)
g(0)
In python 2, you have a few work-arounds; using a mutable to avoid needing to bind it, or (ab)using a function property:
def f(x):
x = [x] # lists are mutable
def g(n):
if n < 10:
x[0] = x[0] + 1 # not assigning, but mutating (x.__setitem__(0, newvalue))
g(n + 1)
g(0)
or
def f(x):
def g(n):
if n < 10:
g.x = g.x + 1
g(n + 1)
g.x = x # attribute on the function!
g(0)
Yes, assigning to names is different than reading their values. Any names that are assigned to in a function are considered local variables of that function unless you specify otherwise.
In Python 2, the only way to "specify otherwise" is to use a global statement to allow you assign to a global variable. In Python 3, you also have the nonlocal statement to assign a value to a variable in a higher (but not necessarily global) scope.
In your example, x is in a higher but non-global scope (the function f). So there is no way to assign to x from within g in Python 2. In Python 3 you could do it with a nonlocal x statement in g.

Python recursion function issue [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 9 years ago.
I am python beginner and at the moment I am struggling with python recursion function:
x = 10
n = 3
def rec(x,n):
if n>0:
#global x2
x2 = x*n
return rec(x2,n-1)
else:
return x2
# function call:
fcall = rec(x,n)
print fcall
What confuses me is that global x2 line. With it, the function is working fine returns 60 as expected, but without it I am getting an error message:
Local variable 'x2' referenced before assignment
Why is that so?
Seems like once n reaches value of 3, and the else condition gets executed, it does not know what x2 is?
If you leave out the global, then the variable is expected to be in local scope within that function. That means that it needs to be assigned somewhere to actually exist. As the only assignment is when the n > 0 condition is true, the return x2 will always try to return a variable that does not exist.
When you add the global, you put that variable into the global scope, making it available everywhere. So it’s assigned and can be returned.
However, it’s not really a good idea to have a function depend on a global variable like that. It seems very unobvious that a global variable is required for it to work. And in fact, it’s not necessary here: Instead of x2 you want to reference x.
def rec (x, n):
if n > 0:
x = x * n
return rec(x, n - 1)
else:
return x
That way, as long as n is still bigger than zero, you multiply the current x by n and temporarily assign it to x again, which you then pass to the recursive call. If n is equal to zero, then the else case applies, and you just return the current x that was passed to the function.
Your problem is that x2 is only a local variable, so when you call the function it doesn't know the old x2 anymore.
By adding the global x2 you put that variable in the global space, so now the function can recognise it.
Check this out: http://gettingstartedwithpython.blogspot.de/2012/05/variable-scope.html
What you actually want to return is x, not x2, because you are passing the value of x2 into the next call of your recursion.
def rec(x,n):
if n>0:
x2 = x*n
return rec(x2,n-1)
else:
return x
Without global x2, assigning to x2 creates a new local variable. With it, assigning to x2 makes it change the global x2 variable. This applies only to assignment, not to looking up variables.
The current stack frame (and thus all local variables associated with it) disappears when the function returns, but globals stay forever and ever and ever (and you should also feel very bad for using them).
And also you can refactor your rec function code to:
def rec(x, n):
return rec(x*n, n-1) if n else x
A typical cause of problems for beginning programmers is the habit of using too many variables. This can make things more complicated and harder to understand. Your code can be made simpler like this:
def rec(x, n):
if n > 0:
return rec(x*n, n-1)
return x
or even this, using the ternary operator:
def rec(x, n):
return rec(x*n, n-1) if n > 0 else x
You can then try it out by just doing:
rec(3, 10)
The sooner you can build a habit creating new variables only when they are needed or improve the readability of the code, the easier your programs will be to write, debug and read.

Categories