This question already has answers here:
Local variables in nested functions
(4 answers)
Closed 7 years ago.
I'm running into issues with Python dispatcher definitions changing each time I add a new function to the dispatcher. An example:
def dispatcher_create():
dispatcher = {}
for i in range(5):
def square():
return i**2
dispatcher[i] = square
for j in range(5):
print dispatcher[j]()
return dispatcher
This code prints out the value 16 five times. I was hoping it would print out 0 1 4 9 16 instead. I'm sure it's an issue with me redefining square every time, but I'm not sure how best to fix it.
The i in return i**2 is bound to the name i, not the value i.
Try this to create a new variable, bound to the appropriate value:
def dispatcher_create():
dispatcher = {}
for i in range(5):
def square(i=i):
return i**2
dispatcher[i] = square
for j in range(5):
print dispatcher[j]()
return dispatcher
dispatcher_create()
No, redefining square() every time is doing what you want, which you can check by printing the contents of dispatcher: all the functions in it will have different id's as desired.
The problem is that you're creating a closure so when you call any of the functions stored in dispatcher they are accessing the latest value of i, rather than using the value that i had when they were defined.
Robᵩ has shown one way around that, by passing i as an arg to square(); here's another way: using another closure which takes i as an arg so it can preserve it for the squaring function it makes.
def dispatcher_create():
dispatcher = {}
def make_square(j):
def square():
return j**2
return square
for i in range(5):
dispatcher[i] = make_square(i)
return dispatcher
dd = dispatcher_create()
print dd
for j in range(5):
print dd[j]()
typical output
{0: <function square at 0xb73a0a3c>, 1: <function square at 0xb73a0dbc>, 2: <function square at 0xb73a0d84>, 3: <function square at 0xb73a5534>, 4: <function square at 0xb73a517c>}
0
1
4
9
16
Robᵩ's version is a little simpler, but this version has the advantage that the functions in dispatcher have the desired argument signature, i.e., they take no argument, whereas Robᵩ's functions take a single argument with a default value that you can over-ride.
FWIW, you could use i instead of j as the parameter for make_square(), since it's just a local variable to make_square(). OTOH, using i there shadows the i in the outer scope, and I feel that using j is slightly less confusing.
I believe it has to do with scope. The i variable remains defined after the for cycle it is used in. If you print the value of i after the for cycle, you see it is 4. If you then call the functions in the next for cycle, the value of i that is in the current scope is used.
As for the solution, i think functools.partial would be a good choice.
from functools import partial
def dispatcher_create():
dispatcher = {}
for i in range(5):
def square(value):
return value**2
dispatcher[i] = partial(square, i)
for j in range(5):
print dispatcher[j]()
return dispatcher
Related
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)
I have a problem where I need to pass the index of an array to a function which I define inline. The function then gets passed as a parameter to another function which will eventually call it as a callback.
The thing is, when the code gets called, the value of the index is all wrong. I eventually solved this by creating an ugly workaround but I am interested in understanding what is happening here. I created a minimal example to demonstrate the problem:
from __future__ import print_function
import threading
def works_as_expected():
for i in range(10):
run_in_thread(lambda: print('the number is: {}'.format(i)))
def not_as_expected():
for i in range(10):
run_later_in_thread(lambda: print('the number is: {}'.format(i)))
def run_in_thread(f):
threading.Thread(target=f).start()
threads_to_run_later = []
def run_later_in_thread(f):
threads_to_run_later.append(threading.Thread(target=f))
print('this works as expected:\n')
works_as_expected()
print('\nthis does not work as expected:\n')
not_as_expected()
for t in threads_to_run_later: t.start()
Here is the output:
this works as expected:
the number is: 0
the number is: 1
the number is: 2
the number is: 3
the number is: 4
the number is: 6
the number is: 7
the number is: 7
the number is: 8
the number is: 9
this does not work as expected:
the number is: 9
the number is: 9
the number is: 9
the number is: 9
the number is: 9
the number is: 9
the number is: 9
the number is: 9
the number is: 9
the number is: 9
Can someone explain what is happening here? I assume it has to do with enclosing scope or something, but an answer with a reference that explains this dark (to me) corner of python scoping would be valuable to me.
I'm running this on python 2.7.11
This is a result of how closures and scopes work in python.
What is happening is that i is bound within the scope of the not_as_expected function. So even though you're feeding a lambda function to the thread, the variable it's using is being shared between each lambda and each thread.
Consider this example:
def make_function():
i = 1
def inside_function():
print i
i = 2
return inside_function
f = make_function()
f()
What number do you think it will print? The i = 1 before the function was defined or the i = 2 after?
It's going to print the current value of i (i.e. 2). It doesn't matter what the value of i was when the function was made, it's always going to use the current value. The same thing is happening with your lambda functions.
Even in your expected results you can see it didn't always work right, it skipped 5 and displayed 7 twice. What is happening in that case is that each lambda is usually running before the loop gets to the next iteration. But in some cases (like the 5) the loop manages to get through two iterations before control is passed to one of the other threads, and i increments twice and a number is skipped. In other cases (like the 7) two threads manage to run while the loop is still in the same iteration and since i doesn't change between the two threads, the same value gets printed.
If you instead did this:
def function_maker(i):
return lambda: print('the number is: {}'.format(i))
def not_as_expected():
for i in range(10):
run_later_in_thread(function_maker(i))
The i variable gets bound inside function_maker along with the lambda function. Each lambda function will be referencing a different variable, and it will work as expected.
A closure in Python captures the free variables, not their current values at the time of the creation of the closure. For example:
def capture_test():
i = 1
def foo():
return i
def bar():
return i
print(foo(), bar()) # 1 1
i = 2
print(foo(), bar()) # 2 2
In Python you can also capture variables and write to them:
def incdec():
counter = 0
def inc(x):
nonlocal counter
counter += x
return counter
def dec(x):
nonlocal counter
counter -= x
return counter
return inc, dec
i1, d1 = incdec()
i2, d2 = incdec()
print(i1(10), i1(20), d1(3)) # 10 30 27
print(i2(100), d2(5), d2(20)) # 100 95 75
print(i1(7), d2(9)) # 34 66
As you see incdec returns a pair of two closures that captured the same variable and that are incrementing/decrementing it. The variable shared by i1/d1 is however different from the variable shared by i2/d2.
One common mistake is for example to expect that
L = []
for i in range(10):
L.append(lambda : i)
for x in L:
print(x())
will display the numbers from 0 to 9... all of the unnamed closures here captured the same variable i used to loop and all of them will return the same value when called.
The common Python idiom to solve this problem is
L.append(lambda i=i: i)
i.e. using the fact that default values for parameters are evaluated at the time the function is created. With this approach each closure will return a different value because they're returning their private local variable (a parameter that has a default).
This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 8 years ago.
I am the new to Python. Here is a problem that I have encountered.
Assume that there is a function called set1(x).
Here is the code:
def set1(x):
x = 1;
When I run this,
m = 5
set1(m)
m
the value of m is still 5.
So how should I code the function if I want the parameter to become 1 whenever I call the set1() function?
You can return the value
def set1():
return 1;
And call it as
m=5
m = set1()
print (m)
It will print 1
Another way but bad method is to make it global
def set1():
global m
m = 1
Functions use a local namespace in which they declare their variables, which means that in most cases when you pass an argument to a function, it will not effect the argument outside of the function (in the global namespace). So while the value changes within the function, it does not change outside of the function.
If you want the function to change the value, you need to return the value as such:
def set1(x):
x=1
return x
>>> m=5
>>> m = set1(m)
>>> m
1
This said, if your argument is mutable, it can change.
def set2(x):
x[0] = 1
>>> m = [2]
>>> set2(m)
>>> m[0]
1
I have a function that returns a number. I want to assign a variable to have this value, but python gives a runtime error when I say temp = foo(i, j) : NameError: name 'foo' is not defined. Note that I've changed the function bodies of bar and foo around, obviously having a function that just returns 1 is useless, but it doesn't change my error.
sum = 0
for i in range(2, 100):
for j in range(2, i):
temp = foo(i, j)
if (temp > 100):
sum = sum + 1
print sum
def bar (n, a):
r = 1
return r
def foo (n, a):
s = bar(n, a)/factorial(5);
return s
def factorial (n):
r = 1
for i in range (2, n + 1):
r *= i;
return r
Names in Python do not exist until they are bound. Move the def foo(...): block above the code that uses foo().
Your definition of foo is AFTER you use it in the file. Put your function definition above the for loop.
As per other answers, your issue is the order in which you run your code: foo hasn't been defined yet when you first call it. Just wanted to add a comment about best practices here.
I always try to put everything in a function and then call any scripts at the bottom. You've probably encountered this pattern before, and it's a good habit to get into:
CONSTANT = 5
def run():
for i in xrange(CONSTANT):
print foo(i) # whatever code you want
def foo(n):
# some method here...
pass
if __name__ == "__main__":
run()
if you run this with python script.py or by hitting f5 in idle, run() will be executed after everything is defined.
By following this pattern you don't have to worry about the order you define your functions in, and you get the added benefit of being able to import foo with other functions without having your script execute during the import, which is probably not a desired behavior.
This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed 6 months ago.
Why does this attempt at creating a list of curried functions not work?
def p(x, num):
print x, num
def test():
a = []
for i in range(10):
a.append(lambda x: p (i, x))
return a
>>> myList = test()
>>> test[0]('test')
9 test
>>> test[5]('test')
9 test
>>> test[9]('test')
9 test
What's going on here?
A function that actually does what I expect the above function to do is:
import functools
def test2():
a = []
for i in range (10):
a.append(functools.partial(p, i))
return a
>>> a[0]('test')
0 test
>>> a[5]('test')
5 test
>>> a[9]('test')
9 test
In Python, variables created in loops and branches aren't scoped. All of the functions you're creating with lambda have a reference to the same i variable, which is set to 9 on the last iteration of the loop.
The solution is to create a function which returns a function, thus scoping the iterator variable. This is why the functools.partial() approach works. For example:
def test():
def makefunc(i):
return lambda x: p(i, x)
a = []
for i in range(10):
a.append(makefunc(i))
return a
Well you can also bind the i to an outer lambda for the lazy.
def p(x, num):
print x, num
def test():
a = []
for i in range(10):
a.append((lambda i :lambda x: p (i, x))(i))
return a
I was always confused as to why this doesn't work. Thanks for the explanation, 'a paid nerd'. I personally prefer this solution:
for i in range(10):
a.append(lambda num, val_i=i: p (val_i, num))
Note the val_i=i default argument of the lambda that enables to capture the instantaneous value of i during the loop whilst still effectively making lambda a function of 1 variable. (BTW: changed your x into num to match p's definition.) I like it better because:
it is very close to the original idea and avoids having to define a new named function, precisely the purpose of a lambda...
avoids importing functools
and avoids imbricating lambdas...
Just did a search and found more detailed explanations for the same problem there: Scope of python lambda functions and their parameters
I asked a similar question, and got two answers. One basically the same as the accepted answer here, and the other which is less clear but slightly more succint.
Dynamically creating a menu in Tkinter. (lambda expressions?)