How do I create a list of lambdas (in a list comprehension/for loop)?
I'm guessing that the lambda you're creating in the list comprehension is bound to the variable i which eventually ends up at 5. Thus, when you evaluate the lambdas after the fact, they're all bound to 5 and end up calculating 25. The same thing is happening with num in your second example. When you evaluate the lambda inside the loop it's num hasn't changed so you get the right value. After the loop, num is 5...
I'm not quite sure what you're going for, so I'm not sure how to suggest a solution. How about this?
def square(x): return lambda : x*x
listOfLambdas = [square(i) for i in [1,2,3,4,5]]
for f in listOfLambdas: print f()
This gives me the expected output:
1
4
9
16
25
Another way to think of this is that a lambda "captures" its lexical environment at the point where it is created. So, if you give it num it doesn't actually resolve that value until its invoked. This is both confusing and powerful.
List comprehension with lambda function
This is because of Pythons late binding closures. You can fix the issue by writing:
def multipliers():
return [lambda x, i=i : i * x for i in range(4)]
Lambda function in list comprehensions
The first one creates a single lambda function and calls it ten times.
The second one doesn't call the function. It creates 10 different lambda functions. It puts all of those in a list. To make it equivalent to the first you need:
[(lambda x: x*x)(x) for x in range(10)]
Or better yet:
[x*x for x in range(10)]
How do you create a python list comprehension of lambdas?
Solution
What you are trying to achieve is defining partial
functions (more generally). You can do this using functools.partial
.
Here's how:
from functools import partial
# Your Code
def func_a(message: str) -> None:
print('a: ' + message)
def func_b(message: str) -> None:
print('b: ' + message)
msg = 'some message'
funcs = [func_a, func_b]
# What I changed: a list of partially-defined functions
funcs_w_args = [partial(func, msg) for func in funcs]
# Now call partially defined functions
for func in funcs_w_args:
func()
Output:
a: some message
b: some message
Refernces
- Documentation for
functools.partial
.
List comprehension and lambdas in Python
The y
in your lambda refers to the last value that y
had in the scope it came from, i.e., 9.
The easiest way to get the behavior you want is to use a default argument in your lambda:
lambda x, y=y: x/y
This captures the value of y
at the moment the lambda function is defined.
You can also do a "double-lambda", calling a function that returns the lambda you want, passing in the desired value of y
:
(lambda y: lambda x: x/y)(y)
Here, the outer lambda provides a new scope each time you call it.
How to generate a list of different lambda functions with list comprehension?
You can use functools.partial
to create specialized functions from a more general one by partial application, which reduces the parameter count by one:
from functools import partial
lambdas = [partial(lambda x: x, i) for i in range(3)]
Here, lambda x: x
is the general identity function taking one argument, and you create three specializations of it, taking no arguments, and returning fixed values.
Lambdas inside list comprehensions and for loops
The lambda
returns the value of i
at the time you call it. Since you call the lambda
after the loop has finished running, the value of i
will always be 9.
You can create a local i
variable in the lambda to hold the value at the time the lambda
was defined:
>>> [j() for j in [lambda i=i:i for i in range(10)]]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Another solution is to create a function that returns the lambda
:
def create_lambda(i):
return lambda:i
>>> [j() for j in [create_lambda(i) for i in range(10)]]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
This works because there is a different closure (holding a different value of i
) created for each invocation of create_lambda
.
Python list comprehension with lambdas
The problem, which is a classic
"gotcha", is
that the i
referenced in the lambda functions is not looked up until the
lambda function is called. At that time, the value of i
is the last value it
was bound to when the for-loop
ended, i.e. 2
.
If you bind i
to a default value in the definition of the lambda
functions, then each i
becomes a local variable, and its default value is evaluated and bound to the function at the time the lambda is defined rather than called.
Thus, when the lambda is called, i
is now looked up in the local scope, and its default value is used:
In [177]: bases = [lambda x, i=i: x**i for i in range(3)]
In [178]: print([b(5) for b in bases])
[1, 5, 25]
For reference:
- Python scopes and namespaces
Python list of lambda functions
The value of i
is not fixed when you defined the function, but when you call the function. You can fix it, but I would recommend not using lambda expressions at all. Instead, define a function that creates your function when called; it makes the scoping easier to handle.
def make_function(i):
def _(x):
return x * i
return _
func_list = [make_function(i) for i in range(n)]
The difference here is that the i
in the function that make_function
returns is not a global variable, but the value of the parameter i
when make_function
is called.
Compare to another possible solution
lambd_list = [lambda x, unused=i: x * unused for i in range(n)]
which requires an otherwise unused parameter to be added to each function. The difference here is the default value of unused
is evaluated at the same time as the lambda expression.
List comprehension with lambda
Since list comprehension and lambda do not fit well in this case, here some functional programming base approaches to, hope, make clear the difference (between a comprehension expression):
A reduce
approach: a list is contracted to a "number" via a functional
from math import factorial
from functools import reduce
n = 10
reduce(lambda i, j: i + 1/factorial(j), range(n), 0)
#2.7182815255731922
here with map
: consecutive 1-to-1 correspondences in which a function is applied termwise. Finally, the sum
functional contracts the list into a "number".
Note: it should be read from right to left, apply the factorial, then the reciprocal and sum it.
sum(map(int(-1).__rpow__, map(factorial, range(n))))
#2.7182815255731922
Related Topics
How to Jump to a Particular Line in a Huge Text File
Plot a Horizontal Line on a Given Plot
Elegant Python Code for Integer Partitioning
How to Un-Escape a Backslash-Escaped String
How to Create a Custom String Representation for a Class Object
How to Convert SQLalchemy Row Object to a Python Dict
How to Convert a Utc Datetime to a Local Datetime Using Only Standard Library
How to Delete Items from a Dictionary While Iterating Over It
What Is the Standard Way to Add N Seconds to Datetime.Time in Python
Unicodedecodeerror: 'Utf8' Codec Can't Decode Byte 0Xa5 in Position 0: Invalid Start Byte
Generating Permutations with Repetitions
Convert Excel Style Date with Pandas
How to Remove a Substring from the End of a String
How to Use Stringio in Python3
Why Doesn't Pygame Draw in the Window Before the Delay or Sleep