So I'm trying to make a list where a lambda functions are the elements of the list. The lambda function calls
another function which I pass an argument to. The problem is that lambda function only 'saves' the last value for all other items in the list. See below
The question is what should I do to get the desired result?
Edit: The stated problem is simplified. I have to use lambda for the solution
This is the code I'm trying to understand the problem:
def f(B):
print(B)
A = [lambda: f(a) for a in ["foo", "faz", "baz"]]
for a in A:
a()
Desired result:
foo
faz
baz
Real result:
baz
baz
baz
if you need to create an array of function calls you can achieve what you are trying to do with the following:
def f(x):
def g():
print(x)
return g
A = [f(a) for a in ["foo", "faz", "baz"]]
for a in A:
a()
output
foo
faz
baz
While lambda accesses the context it's defined in, a for loop doesn#t create a new context each time it runs. That would be too inefficient.
Thus, by the time your code actually calls the lambda functions that context has ended and a contains the last value the loop assigned to it.
Correct code:
def f(B):
print(B)
A = ["foo", "faz", "baz"]
for a in A:
f(a)
If this answer is not sufficient, please clarify why do you need that lambda in the first place.
For loop in lambda saves last item of list so its better to write it way out lambda
like this:
def b():
A = ["foo","faz","baz"]
For a in A:
Print(a)
and output is:
foo
faz
baz
Related
Recently I started playing around with Python and I came around something peculiar in the way closures work. Consider the following code:
adders=[None, None, None, None]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
It builds a simple array of functions that take a single input and return that input added by a number. The functions are constructed in for loop where the iterator i runs from 0 to 3. For each of these numbers a lambda function is created which captures i and adds it to the function's input. The last line calls the second lambda function with 3 as a parameter. To my surprise the output was 6.
I expected a 4. My reasoning was: in Python everything is an object and thus every variable is essential a pointer to it. When creating the lambda closures for i, I expected it to store a pointer to the integer object currently pointed to by i. That means that when i assigned a new integer object it shouldn't effect the previously created closures. Sadly, inspecting the adders array within a debugger shows that it does. All lambda functions refer to the last value of i, 3, which results in adders[1](3) returning 6.
Which make me wonder about the following:
What do the closures capture exactly?
What is the most elegant way to convince the lambda functions to capture the current value of i in a way that will not be affected when i changes its value?
For a more accessible, practical version of the question, specific to the case where a loop (or list comprehension, generator expression etc.) is used, see Creating functions (or lambdas) in a loop (or comprehension). This question is focused on understanding the underlying behaviour of the code in Python.
If you got here trying to fix a problem with making buttons in Tkinter, try tkinter creating buttons in for loop passing command arguments for more specific advice.
See What exactly is contained within a obj.__closure__? for technical details of how Python implements closures. See What is the difference between Early and Late Binding? for related terminology discussion.
you may force the capture of a variable using an argument with a default value:
>>> for i in [0,1,2,3]:
... adders[i]=lambda a,i=i: i+a # note the dummy parameter with a default value
...
>>> print( adders[1](3) )
4
the idea is to declare a parameter (cleverly named i) and give it a default value of the variable you want to capture (the value of i)
What do the closures capture exactly?
Closures in Python use lexical scoping: they remember the name and scope of the closed-over variable where it is created. However, they are still late binding: the name is looked up when the code in the closure is used, not when the closure is created. Since all the functions in your example are created in the same scope and use the same variable name, they always refer to the same variable.
There are at least two ways to get early binding instead:
The most concise, but not strictly equivalent way is the one recommended by Adrien Plisson. Create a lambda with an extra argument, and set the extra argument's default value to the object you want preserved.
More verbosely but also more robustly, we can create a new scope for each created lambda:
>>> adders = [0,1,2,3]
>>> for i in [0,1,2,3]:
... adders[i] = (lambda b: lambda a: b + a)(i)
...
>>> adders[1](3)
4
>>> adders[2](3)
5
The scope here is created using a new function (another lambda, for brevity), which binds its argument, and passing the value you want to bind as the argument. In real code, though, you most likely will have an ordinary function instead of the lambda to create the new scope:
def createAdder(x):
return lambda y: y + x
adders = [createAdder(i) for i in range(4)]
For completeness another answer to your second question: You could use partial in the functools module.
With importing add from operator as Chris Lutz proposed the example becomes:
from functools import partial
from operator import add # add(a, b) -- Same as a + b.
adders = [0,1,2,3]
for i in [0,1,2,3]:
# store callable object with first argument given as (current) i
adders[i] = partial(add, i)
print adders[1](3)
Consider the following code:
x = "foo"
def print_x():
print x
x = "bar"
print_x() # Outputs "bar"
I think most people won't find this confusing at all. It is the expected behaviour.
So, why do people think it would be different when it is done in a loop? I know I did that mistake myself, but I don't know why. It is the loop? Or perhaps the lambda?
After all, the loop is just a shorter version of:
adders= [0,1,2,3]
i = 0
adders[i] = lambda a: i+a
i = 1
adders[i] = lambda a: i+a
i = 2
adders[i] = lambda a: i+a
i = 3
adders[i] = lambda a: i+a
Here's a new example that highlights the data structure and contents of a closure, to help clarify when the enclosing context is "saved."
def make_funcs():
i = 42
my_str = "hi"
f_one = lambda: i
i += 1
f_two = lambda: i+1
f_three = lambda: my_str
return f_one, f_two, f_three
f_1, f_2, f_3 = make_funcs()
What is in a closure?
>>> print f_1.func_closure, f_1.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,) 43
Notably, my_str is not in f1's closure.
What's in f2's closure?
>>> print f_2.func_closure, f_2.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,) 43
Notice (from the memory addresses) that both closures contain the same objects. So, you can start to think of the lambda function as having a reference to the scope. However, my_str is not in the closure for f_1 or f_2, and i is not in the closure for f_3 (not shown), which suggests the closure objects themselves are distinct objects.
Are the closure objects themselves the same object?
>>> print f_1.func_closure is f_2.func_closure
False
In answer to your second question, the most elegant way to do this would be to use a function that takes two parameters instead of an array:
add = lambda a, b: a + b
add(1, 3)
However, using lambda here is a bit silly. Python gives us the operator module, which provides a functional interface to the basic operators. The lambda above has unnecessary overhead just to call the addition operator:
from operator import add
add(1, 3)
I understand that you're playing around, trying to explore the language, but I can't imagine a situation I would use an array of functions where Python's scoping weirdness would get in the way.
If you wanted, you could write a small class that uses your array-indexing syntax:
class Adders(object):
def __getitem__(self, item):
return lambda a: a + item
adders = Adders()
adders[1](3)
One way to sort out the scope of i is to generate the lambda in another scope (a closure function), handing over the necessary parameters for it to make the lambda:
def get_funky(i):
return lambda a: i+a
adders=[None, None, None, None]
for i in [0,1,2,3]:
adders[i]=get_funky(i)
print(*(ar(5) for ar in adders))
giving 5 6 7 8 of course.
My understanding of mutability and immutability in Python is, say we have a variable foo, if there exists a way to change how foo looks like (by using print) without changing its id, then foo is mutable. Otherwise, it's immutable.
For example, you can do this for a list,
foo = [1, 2, 3]
print(foo, id(foo))
foo[0] = 100
print(foo, id(foo))
but no way for int.
But what about function? First of all, is my definitions of mutability and immutability given above correct? If yes, can you find a way to mutate function without changing its id in order to prove it's mutable?
You can explicitly change the code of a function without affecting its id (here is code using python 2.7):
>>> def f():
... print "f"
...
>>> def g():
... print "g"
...
>>> id(f)
140305904690672
>>> f()
f
>>> f.func_code = g.func_code
>>> id(f)
140305904690672
>>> f()
g
Recently I started playing around with Python and I came around something peculiar in the way closures work. Consider the following code:
adders=[None, None, None, None]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
It builds a simple array of functions that take a single input and return that input added by a number. The functions are constructed in for loop where the iterator i runs from 0 to 3. For each of these numbers a lambda function is created which captures i and adds it to the function's input. The last line calls the second lambda function with 3 as a parameter. To my surprise the output was 6.
I expected a 4. My reasoning was: in Python everything is an object and thus every variable is essential a pointer to it. When creating the lambda closures for i, I expected it to store a pointer to the integer object currently pointed to by i. That means that when i assigned a new integer object it shouldn't effect the previously created closures. Sadly, inspecting the adders array within a debugger shows that it does. All lambda functions refer to the last value of i, 3, which results in adders[1](3) returning 6.
Which make me wonder about the following:
What do the closures capture exactly?
What is the most elegant way to convince the lambda functions to capture the current value of i in a way that will not be affected when i changes its value?
For a more accessible, practical version of the question, specific to the case where a loop (or list comprehension, generator expression etc.) is used, see Creating functions (or lambdas) in a loop (or comprehension). This question is focused on understanding the underlying behaviour of the code in Python.
If you got here trying to fix a problem with making buttons in Tkinter, try tkinter creating buttons in for loop passing command arguments for more specific advice.
See What exactly is contained within a obj.__closure__? for technical details of how Python implements closures. See What is the difference between Early and Late Binding? for related terminology discussion.
you may force the capture of a variable using an argument with a default value:
>>> for i in [0,1,2,3]:
... adders[i]=lambda a,i=i: i+a # note the dummy parameter with a default value
...
>>> print( adders[1](3) )
4
the idea is to declare a parameter (cleverly named i) and give it a default value of the variable you want to capture (the value of i)
What do the closures capture exactly?
Closures in Python use lexical scoping: they remember the name and scope of the closed-over variable where it is created. However, they are still late binding: the name is looked up when the code in the closure is used, not when the closure is created. Since all the functions in your example are created in the same scope and use the same variable name, they always refer to the same variable.
There are at least two ways to get early binding instead:
The most concise, but not strictly equivalent way is the one recommended by Adrien Plisson. Create a lambda with an extra argument, and set the extra argument's default value to the object you want preserved.
More verbosely but also more robustly, we can create a new scope for each created lambda:
>>> adders = [0,1,2,3]
>>> for i in [0,1,2,3]:
... adders[i] = (lambda b: lambda a: b + a)(i)
...
>>> adders[1](3)
4
>>> adders[2](3)
5
The scope here is created using a new function (another lambda, for brevity), which binds its argument, and passing the value you want to bind as the argument. In real code, though, you most likely will have an ordinary function instead of the lambda to create the new scope:
def createAdder(x):
return lambda y: y + x
adders = [createAdder(i) for i in range(4)]
For completeness another answer to your second question: You could use partial in the functools module.
With importing add from operator as Chris Lutz proposed the example becomes:
from functools import partial
from operator import add # add(a, b) -- Same as a + b.
adders = [0,1,2,3]
for i in [0,1,2,3]:
# store callable object with first argument given as (current) i
adders[i] = partial(add, i)
print adders[1](3)
Consider the following code:
x = "foo"
def print_x():
print x
x = "bar"
print_x() # Outputs "bar"
I think most people won't find this confusing at all. It is the expected behaviour.
So, why do people think it would be different when it is done in a loop? I know I did that mistake myself, but I don't know why. It is the loop? Or perhaps the lambda?
After all, the loop is just a shorter version of:
adders= [0,1,2,3]
i = 0
adders[i] = lambda a: i+a
i = 1
adders[i] = lambda a: i+a
i = 2
adders[i] = lambda a: i+a
i = 3
adders[i] = lambda a: i+a
Here's a new example that highlights the data structure and contents of a closure, to help clarify when the enclosing context is "saved."
def make_funcs():
i = 42
my_str = "hi"
f_one = lambda: i
i += 1
f_two = lambda: i+1
f_three = lambda: my_str
return f_one, f_two, f_three
f_1, f_2, f_3 = make_funcs()
What is in a closure?
>>> print f_1.func_closure, f_1.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,) 43
Notably, my_str is not in f1's closure.
What's in f2's closure?
>>> print f_2.func_closure, f_2.func_closure[0].cell_contents
(<cell at 0x106a99a28: int object at 0x7fbb20c11170>,) 43
Notice (from the memory addresses) that both closures contain the same objects. So, you can start to think of the lambda function as having a reference to the scope. However, my_str is not in the closure for f_1 or f_2, and i is not in the closure for f_3 (not shown), which suggests the closure objects themselves are distinct objects.
Are the closure objects themselves the same object?
>>> print f_1.func_closure is f_2.func_closure
False
In answer to your second question, the most elegant way to do this would be to use a function that takes two parameters instead of an array:
add = lambda a, b: a + b
add(1, 3)
However, using lambda here is a bit silly. Python gives us the operator module, which provides a functional interface to the basic operators. The lambda above has unnecessary overhead just to call the addition operator:
from operator import add
add(1, 3)
I understand that you're playing around, trying to explore the language, but I can't imagine a situation I would use an array of functions where Python's scoping weirdness would get in the way.
If you wanted, you could write a small class that uses your array-indexing syntax:
class Adders(object):
def __getitem__(self, item):
return lambda a: a + item
adders = Adders()
adders[1](3)
One way to sort out the scope of i is to generate the lambda in another scope (a closure function), handing over the necessary parameters for it to make the lambda:
def get_funky(i):
return lambda a: i+a
adders=[None, None, None, None]
for i in [0,1,2,3]:
adders[i]=get_funky(i)
print(*(ar(5) for ar in adders))
giving 5 6 7 8 of course.
Consider the following functions:
def a():
print "a"
def b():
print "b"
Is there a way to pick a function to run randomly? I tried using:
random.choice([a(),b()])
but it returns both functions, I just want it to return one function.
Only call the selected function, not both of them:
random.choice([a,b])()
Below is a demonstration:
>>> import random
>>> def a():
... print "a"
...
>>> def b():
... print "b"
...
>>> random.choice([a,b])()
a
>>> random.choice([a,b])()
b
>>>
Your old code called both functions when the list [a(),b()] was created, causing Python to print both a and b. Afterwards, it told random.choice to choose from the list [None, None]1, which does nothing. You can see this from the demonstration below:
>>> [a(),b()]
a
b
[None, None]
>>>
The new code however uses random.choice to randomly select a function object from the list [a,b]:
>>> random.choice([a,b])
<function b at 0x01AFD970>
>>> random.choice([a,b])
<function a at 0x01AFD930>
>>>
It then calls only that function.
1Functions return None by default. Since a and b lack return-statements, they each return None.
Is it what you want?
random.choice([a,b])()
I have this following block of code and I am getting this message in the shell...
"function word_switch at 0x102b67a70"
What does this mean and why does Python print this instead of returning the function?
Thanks
D= ['foo', 'bar', 'OMG']
def word_switch (D: list) -> list:
for i in D:
reversed(i)
return word_switch
print(word_switch(D))
You need to generate the reversed list and return it, not the function itself. You can do this
D = ['foo', 'bar', 'OMG']
def word_switch (D: list) -> list:
return ["".join(reversed(i)) for i in D]
#return [i[::-1] for i in D] # Using slicing
print(word_switch(D))
Output
['oof', 'rab', 'GMO']
What does it mean? The output means that the function word_switch lives in that memory position.
Why are you getting it? Because you asked for it. Beware that in the way your function is defined, when you call it you get the function object itself and then you print it.
It happens the very same thing every time you print a function object, for instance:
>>> def f(x):
... x
>>> print f
<function f at 0xb72eda3c>
>>>
If what you want is just reverse a list you can simply use the reverse method of lists objects as suggested in the comments to the OP. It is not necessary to create you own function. If , for some reason, you need your own function then you can write it in the way suggested by #thefourtheye in his answer.