This question already has answers here:
Local variables in nested functions
(4 answers)
Closed 5 years ago.
I wanted to create a list of lambdas, but it didn't quite work out as I hoped.
L = [(lambda x: x/y) for y in range(10)]
I expected every function in the list to divide its argument by its index, but all functions only divide by the last index.
>>> L[1](5)
0.5555555555555556
>>> L[5](5)
0.5555555555555556
>>> 5/9
0.5555555555555556
Is this kind of list comprehension, where every lambda has its own copy of ypossible 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.
You need the loop and the lambda to be in different scopes.
def make_divider(y):
return lambda x: x / y
L = [make_divider(y) for y in range(10)]
print(L[2](5) == 5 / 2)
print(L[4](5) == 5 / 4)
Related
This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Lambda in a loop [duplicate]
(4 answers)
Closed last year.
I am trying to generate a list of lambdas that I will later apply to an object, but when I try to do it via a comprehension or a loop over a list, the reference to the variable is kept, rather than the value itself. Let me illustrate.
Assume your object class is something like this:
class Object:
def function(self, x):
print(x)
So when you create the object and invoke it you get something like this:
o = Object()
o.function(0)
>>> 0
Now, if I manually construct my list of lambdas it would look like this:
lambdas = [
lambda x: x.function(0),
lambda x: x.function(1),
lambda x: x.function(2)
]
Which I can then apply to my previously created object:
for l in lambdas:
l(o)
>>> 0
>>> 1
>>> 2
However, when I generate the lambda list from another list, I only get the reference to the latest element of the list:
lambdas = [lambda x: x.function(i) for i in range(2)]
for l in lambdas:
l(o)
>>> 2
>>> 2
>>> 2
On closer inspection I can see that each lambda has a different memory address, so they are NOT references to the same function.
So I can only assume that the lambda is keeping a reference to i which has a final value of 2 and therefore when invoked, it takes the value.
So my question is if its possible to set the value of the variable inside the lambda before invocation?
Note: The usa case for a list of lambdas is to pass to the agg function of a Pandas groupby on a DataFrame. I am not looking for a solution to the pandas problem, but curious about the general solution.
Generator Option
Just change lambdas to a generator instead of a list, this will cause it redefine i on every call:
lambdas = (lambda x: x.function(i) for i in range(2))
for l in lambdas:
print(l(o))
Full code:
class Object:
def function(self, x):
print(x)
o = Object()
o.function(0) #manual call
lambdas = (lambda x: x.function(i) for i in range(2))
for l in lambdas:
l(o)
Output:
0 #output from manual call
0 #output from generator
1 #output from generator
List Option
If you need a list for things like lambdas[0](o) you can send i to lambda each iteration by using i=i like so:
lambdas = [lambda x, i=i: x.function(i) for i in range(2)]
Example of second option:
class Object:
def function(self, x):
print(x)
o = Object()
lambdas = [lambda x, i=i: x.function(i) for i in range(2)] #notice the cahnge
for i in range(len(lambdas)):
lambdas[i](o) #notice the change
Output:
0
1
What takes place is that in this expression, the "living" (nonlocal) i variable is
used inside each lambda created. And at the end of the for loop, its value is the last value taken - which will be used when the lambdas are actually called.
lambdas = [lambda x: x.function(i) for i in range(2)]
The fix for that is to create an intermediary namespace which will "freeze" the nonlocal variable value at the time the lambda is created. This is usually done with another lambda:
lambdas = [(lambda i: (lambda x: x.function(i)))(i) for i in range(2)]
So, bear with me - in the above expression, for each execution of the for i loop, a new, disposable lambda i is created and called imediatelly with the current value of the i used in the for. Inside it, this value is bound to a local i variable, that is unique to this disposable lambda i (in Python internal workings, it gets its own "cell"). This unique iis then used in the second, permanent, lambda x expression. Whenever that one is called, it will use the i value persisted in the outter lambda i call. The external lambda i then returns the lambda x expression as its result, but its nonlocal i is bound to the value used inside the lambda i, not the one used in the for i.
This is a common problem in Python, but can't be fixed because it is part of how the language works.
There is a shorter, and working, form to "freeze" the i from for i when each lambda i is created, that does not require an outer function scope: when a function is created, the values passed as default for its parameters are stored along with the function. Then, if one stores the current value of i as a default value, it won't change when the variable i itself does:
lambdas = [lambda x, i=i: x.function(i) for i in range(2)]
Here, in the lambda x, i=i: snippet, the value of i in the scope the lambda is created is stored as the default value for the parameter i, which works as a local (in contrast with a nonlocal) variable inside the lambda function itself.
This question already has answers here:
Local variables in nested functions
(4 answers)
Closed 5 years ago.
I wanted to create a list of lambdas, but it didn't quite work out as I hoped.
L = [(lambda x: x/y) for y in range(10)]
I expected every function in the list to divide its argument by its index, but all functions only divide by the last index.
>>> L[1](5)
0.5555555555555556
>>> L[5](5)
0.5555555555555556
>>> 5/9
0.5555555555555556
Is this kind of list comprehension, where every lambda has its own copy of ypossible 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.
You need the loop and the lambda to be in different scopes.
def make_divider(y):
return lambda x: x / y
L = [make_divider(y) for y in range(10)]
print(L[2](5) == 5 / 2)
print(L[4](5) == 5 / 4)
This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed 6 months ago.
I was surprised that this assertion fails:
x = 42
x = lambda: x
assert x() == 42
It seems that x ends up recursively referring to itself, so that x(), x()(), etc. are all functions.
What is the rule used to parse this, and where is this documented?
By the way (not unexpectedly given the above), the original value of x has no references left after the lambda definition:
class X:
def __del__(self): print('deleting')
x = X()
x = lambda: x # 'deleting' is printed here
The variable x is created by the first assignment, and rebound with the second assignment.
Since the x in the lambda isn't evaluated until the lambda is called, calling it will evaluate to the most recently assigned value.
Note that this is not dynamic scoping - if it were dynamic, the following would print "99", but it prints "<function ...":
x = 42
x = lambda: x
def test(f):
x = 99
print(f())
test(x)
The first assignment is irrelevant; the x in the body of the lambda is bound late:
x = lambda: x # no need for a prior assignment
x = lambda: y # notice: no NameError occurs, *until it is called*
This is the same reason that creating lambdas in a loop is tricky, and is also used to make trees with the standard library defaultdict:
tree = lambda: defaultdict(tree)
t = tree()
t['foo']['bar']['baz'] = 'look ma, no intermediate steps'
A lambda is an anonymous function object. Python completely resolves whatever is on the right side of an equation to a single anonymous object and then resolves whatever is on the left side for assignment.
x = lambda: x
first compiles lambda: x into a function object that returns whatever happens to be in x at the time it is called. It then rebinds x with this function object, deleting whatever object happened to be there before.
Now x is a function that returns whatever is in x... which is a function that returns whatever is in x, etc... So you can write x()()()()()() as many times as you want, and still get that orginal lambda:x function object.
Python functions have a local namespace but only variables assigned in the function reside there. Since x isn't assigned in the lambda, it's resolved in the containing scope - that is, the module level "x". An identical piece of code is
def x():
return x
Contrast this with
def x():
x = 1
return x
Now, the parameter x is a local variable and is unrelated to the global x.
This question already has answers here:
Local variables in nested functions
(4 answers)
What do lambda function closures capture?
(7 answers)
Closed 2 years ago.
Note: This concept is touched upon in Lambda function in list comprehensions, but not to a sufficient depth for my understanding.
We start with an example (in Python) of a closure:
def enclosing_function(free_variable):
def nested_function(x):
return x + free_variable
return nested_function
closure = enclosing_function(1) # closure is the "addition by 1" function
print(closure(37) == 38) # prints: True
A closure is created by evaluating an enclosing function. The enclosing function contains a nested function, the return value of which contains the (evaluated) free variable. Mathematically, this is equivalent to evaluating a non-empty proper subset of the input variables of a function of more than one variable. In particular, the above example is equivalent to setting y = 1 in the function f(x, y) = x + y.
An alternative implementation is to have the enclosing function return an anonymous function. In this case, the return value is called an anonymous closure:
def enclosing_function(free_variable):
return lambda x: x + free_variable
We also have anonymous enclosing functions:
print((lambda free_variable: (lambda x: x + free_variable))(1)(37)) # prints: 38
Now, let's set NUMBER_OF_LAMBDAS = 3 and look at two ways of constructing a list of
anonymous functions:
a = [lambda x: y for y in range(NUMBER_OF_LAMBDAS)]
b = [lambda x: 0, lambda x: 1, lambda x: 2]
One would naively assume that the lists are the same, but in fact this is not true:
for i in range(NUMBER_OF_LAMBDAS):
z = a[i]('foo')
print(f'a_{i}(\'foo\') = {z}')
# Prints:
# a_0('foo') = 2
# a_1('foo') = 2
# a_2('foo') = 2
for i in range(NUMBER_OF_LAMBDAS):
z = b[i]('bar')
print(f'b_{i}(\'bar\') = {z}')
# Prints:
# b_0('bar') = 0
# b_1('bar') = 1
# b_2('bar') = 2
The aforementioned StackOverflow article shows that to obtain the expected behavior, one must explicitly define and evaluate an anonymous enclosing function in the list comprehension:
c = [(lambda w: (lambda x: w))(y) for y in range(NUMBER_OF_LAMBDAS)]
for i in range(NUMBER_OF_LAMBDAS):
z = c[i]('foobar')
print(f'c_{i}(\'foobar\') = {z}')
# Prints:
# c_0('foobar') = 0
# c_1('foobar') = 1
# c_2('foobar') = 2
a is a list of anonymous closures. c is a list of evalutions of anonymous enclosing functions. Why are these two lists different?
Just for curiosity. Discovered Lambdas a few days ago. I was jus wondering if something like that can be done:
(Tried on the interpret but none of my tries seemed to work)
p = lambda x: (lambda x: x%2)/2
There's no explicit purpose. I just did'nt find a satisfactory answer. I may have misunderstood Lambdas.
You can use an inner lambda to return another function, based on the outer parameters:
mul = lambda x: (lambda y: y * x)
times4 = mul(4)
print times4(2)
You aren't actually calling the inner lambda:
p = lambda x: (lambda x: x%2)(x)/2
Note in Python 2 this example will always return 0 since the remainder from dividing by 2 will be either 0 or 1 and integer-dividing that result by 2 will result in a truncated 0.
(lambda x: x%2) is a function, and dividing a function by 2 doesn't make any sense. You probably want to call it and divide what the value it returned.