How to Create a List of Lambdas (In a List Comprehension/For Loop)

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



Leave a reply



Submit