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.
Related
I'm new to python and I want to convert a loop "for" into a function. My loop I created enables me to multiply all the number of a list and print the result. This is my loop:
a=[1,2,3,4,9]
y=1
for x in a:
y=y*x
print(y)
As you can see I tried it with a certain list and I always put y=1 to start my loop and it works very well but when I want to create a function of that loop it fails, so far I tried that:
a=[]
y=1
def produit_entier(a):
for x in a:
y=y*x
return y
a=[1,2,3,4,9]
y=1
print(produit_entier(a))
As you can see I tried it with a certain list and when I run my code it tells me "local variable 'y' referenced before assignment", and when I remove the "y=1" line and put it right after the "for x in a:" this message disappear but the result is always 1.
So I'm lost here, my function is almost exactly the same as my loop, but my loop works very well and not my function, so I would really appreciate help here. Thx in advance
The y needs to be declared inside the function, since it is used by the function.
def produit_entier(a):
y = 1
for x in a:
y=y*x
return y
Karim!
First of all, there is a problem with the return statement. You placed it the wrong way, it should be like this:
def produit_entier(a):
for x in a:
y=y*x
return y
Secondly, if you want to modify a value inside a function, which is not passed or declared inside the function - you gotta specify a global keyword to make it accessible for the modification (if you only want to read it - you do not have to specify global keyword):
def produit_entier(a):
global y
for x in a:
y=y*x
return y
Thirdly, you do not have to return a value of y though it is a global one, just print it after.
And fourthly, using global variables is actually a bad practice (since you might modify if accidentally somewhere you do not want to and it will be difficult to find). I suggest you either declare it inside the function:
def produit_entier(a):
y = 1
for x in a:
y=y*x
return y
Or just pass a value as an argument:
def produit_entier(a, y):
for x in a:
y=y*x
return y
Best of luck!
I'll provide an alternative answer using reduce:
from functools import reduce
def produit_entier(a):
return reduce(lambda x,y: x*y,a)
Or just the built-in reduce(int.__mul__, a)
I am reading Hackers and Painters and am confused by a problem mentioned by the author to illustrate the power of different programming languages.
The problem is:
We want to write a function that generates accumulators—a function that takes a number n, and returns a function that takes another number i and returns n incremented by i. (That’s incremented by, not plus. An accumulator has to accumulate.)
The author mentions several solutions with different programming languages. For example, Common Lisp:
(defun foo (n)
(lambda (i) (incf n i)))
and JavaScript:
function foo(n) { return function (i) { return n += i } }
However, when it comes to Python, the following codes do not work:
def foo(n):
s = n
def bar(i):
s += i
return s
return bar
f = foo(0)
f(1) # UnboundLocalError: local variable 's' referenced before assignment
A simple modification will make it work:
def foo(n):
s = [n]
def bar(i):
s[0] += i
return s[0]
return bar
I am new to Python. Why doesn the first solution not work while the second one does? The author mentions lexical variables but I still don't get it.
s += i is just sugar for s = s + i.*
This means you assign a new value to the variable s (instead of mutating it in place). When you assign to a variable, Python assumes it is local to the function. However, before assigning it needs to evaluate s + i, but s is local and still unassigned -> Error.
In the second case s[0] += i you never assign to s directly, but only ever access an item from s. So Python can clearly see that it is not a local variable and goes looking for it in the outer scope.
Finally, a nicer alternative (in Python 3) is to explicitly tell it that s is not a local variable:
def foo(n):
s = n
def bar(i):
nonlocal s
s += i
return s
return bar
(There is actually no need for s - you could simply use n instead inside bar.)
*The situation is slightly more complex, but the important issue is that computation and assignment are performed in two separate steps.
An infinite generator is one implementation. You can call __next__ on a generator instance to extract successive results iteratively.
def incrementer(n, i):
while True:
n += i
yield n
g = incrementer(2, 5)
print(g.__next__()) # 7
print(g.__next__()) # 12
print(g.__next__()) # 17
If you need a flexible incrementer, one possibility is an object-oriented approach:
class Inc(object):
def __init__(self, n=0):
self.n = n
def incrementer(self, i):
self.n += i
return self.n
g = Inc(2)
g.incrementer(5) # 7
g.incrementer(3) # 10
g.incrementer(7) # 17
In Python if we use a variable and pass it to a function then it will be Call by Value whatever changes you make to the variable it will not be reflected to the original variable.
But when you use a list instead of a variable then the changes that you make to the list in the functions are reflected in the original List outside the function so this is called call by reference.
And this is the reason for the second option does work and the first option doesn't.
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.
def makeInc (x, step):
def next():
nonlocal x, step
x = x + step
return x
return next
x = makeInc (0, 1)
y = makeInc (0, 10)
x1=x()
x2=x()
y1=y()
y2=y()
print( x1, x2, y1, y2)
The output is 1 2 10 20.
I am not sure why it gives these outputs, can anyone explain it in detail? Thanks!
The function makeInc() is a "factory" that makes function objects and returns them. The nonlocal declaration makes the function "close over" a variable. Usually you would make an explicit variable and close over that; in this case, the nonlocal declaration is closing over an argument variable from makeInc().
If you want to learn about closures and nonlocal here are a few references:
http://www.mondoinfo.com/blog/C182263547/E20060918200706/index.html
Python nonlocal statement
So, makeInc() makes a function object that has a start value and a "step" by which the start value will be incremented. Once you have made the custom function object, the final code calls the functions and gets the incrementing values.
Okay, I am currently doing a project to make a blackjack game in python and I'm having some trouble. One of my issues is I dont know when to define a variable as global, specifically in functions with if statements. If I have a global variable outside the if statement, do I have to claim that the variable is global within the if statement as well? For example:
x = 5
def add():
global x <--- ?
x += 1
if x == 7:
global x <--- ?
x = 5
I'm pretty sure I need the "global x" at the 1st question mark, but what about at the second question mark? Would I still need to put a "global x" within my if statement if I wanted my if statement to update a global variable? Or does the global x at the beginning of the function make the x's inside the if statement global? Also, if I wanted to return x here, where should I do it?
Only one global statement is enough.
From docs:
The global statement is a declaration which holds for the entire
current code block.
x = 5
def add():
global x
x += 1
if x == 7:
x = 5
Also, if I wanted to return x here, where should I do it?
If you're using global in your function then the return x must come after the global x statement, if you didn't use any global statement and also didn't define any local variable x then you can return x anywhere in the function.
If you've defined a local variable x then return x must come after the definition.