I am new to python and I am trying to understand the logic here:
What does lambda x=x mean? in the complete function below:
tables = [lambda x=x: x*10 for x in range(1, 11)]
for table in tables:
print(table())
There are two different variables named x here.
The first one is the parameter, which is a local variable in the function being defined.
The second is a variable visible in the scope where the function is being defined. Its value is stored as the default value to use for the first variable x if no argument is passed when the function is called.
It is far less confusing if you just use two different names for the two different variables:
tables = [lambda x=y: x*10 for y in range(1, 11)]
This is the short way of writing
tables = []
tables.append(lambda x=1: x*10)
tables.append(lambda x=2: x*10)
# etc.
Based on how each function is called in the following loop, the intention appears to be to never actually pass an argument when the function is called, and that what we really want is to automate something like
tables = []
tables.append(lambda : 1 * 10)
tables.append(lambda : 2 * 10)
# etc.
The naive approach
tables = [lambda: x*10 for x in range(1, 11)]
fails because x is a free variable in the body of the function; it does not get replaced with the value of x at the time the function is called. Doing this, you end up with a list of 10 identical function, all of which depend on the last value assigned to x before the function is called.
By binding a default value that is evaluated immediately to the parameter, you "inject" the current value of x into the function right away, so that you end up with a list of 10 different functions.
tables = [lambda y = x: x*10 for x in range(1, 11)]
for table in tables:
print(table())
The output is 10 100s printed one below the other
I an unable to understand the logic
Related
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.
I am slightly confused by map in python. The function for mapaccepts 2 parameters: `map(function, variables).
Why is the code below able to take in multiply and add as variables but the second code isn't able to? In a usual case, multiply should be passed in in as a function, check out range.
def multiply(x):
return x * x
def add(x):
return x + x
funcs = [multiply, add]
for i in range (1, 5):
value = list(map(lambda x: x(i), funcs))
print(value)
This is the second code:
def multiply(x):
return x * x
def add(x):
return x + x
funcs = (add, multiply)
multi_func = (multiply)
for i in range (1, 5):
value = list(map(lambda x: x(i), multi_func))
print(value)
Is it possible to make use of 1 function and still use for in range?
Using range:
map(multiply, range(1, 5))
map applies its first argument, which is a function, to each element of the iterable which is the second argument. The function is applied lazily. That means it's done only when you iterate over the map object, e.g., when you create a list of of it.
Let's take a look at your first code. funcs = [multiply, add] creates a list, which is iterable, of two elements. Both elements are functions. This is normal in Python, because functions are just regular objects, and can be passed around, assigned, have attributes, etc. The loop
for i in range (1, 5):
value = list(map(lambda x: x(i), funcs))
print(value)
Repeats form 1 to 4. At each iteration it maps lambda x: x(i) to the functions in funcs. When i = 1, the map ends up doing multiply(1), add(1). When i = 2, it's multiply(2), add(2), and so on.
The second code doesn't work because of a typo. (x) is just x, but (x,) is a one-element tuple whose first element is x. map requires the second argument to be iterable, so passing in a function won't do. If you want to map to a single function, you need to supply an iterable with one element: multi_func = (multiply,).
Once corrected, the second version will print multiply(1) when i = 1, multiply(2) when i = 2, etc.
Something like list(map(multiply, range(1, 5))) will in fact be an easier way to write the second version. You can also do something similar with the first code, using zip:
zip(map(func, range(1, 5)) for func in funcs)
I have come across this example from Python hitchhikers guide:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
The example above is the solution to some issues caused with late binding, where variables used in closures are looked up at the time the inner function is called.
What does the i=i mean and why is it making such difference?
It's actually not just for lambdas; any function that takes default parameters will use the same syntax. For example
def my_range(start, end, increment=1):
ans = []
while start < end:
ans.append(start)
start += increment
return ans
(This is not actually how range works, I just thought it would be a simple example to understand). In this case, you can call my_range(5,10) and you will get [5,6,7,8,9]. But you can also call my_range(5,10,increment=2), which will give you [5, 7, 9].
You can get some surprising results with default arguments. As this excellent post describes, the argument is bound at function definition, not at function invocation as you might expect. That causes some strange behavior, but it actually helps us here. Consider the incorrect code provided in your link:
def create_multipliers():
return [lambda x : i * x for i in range(5)]
for multiplier in create_multipliers():
print multiplier(2)
When you call multiplier(2), what is it actually doing? It's taking your input parameter, 2, and returning i * 2. But what is i? The function doesn't have any variable called i in its own scope, so it checks the surrounding scope. In the surrounding scope, the value of i is just whatever value you left it -- in this case 4. So every function gives you 8.
On the other hand, if you provide a default parameter, the function has a variable called i in its own scope. What's the value of i? Well, you didn't provide one, so it uses its default value, which was bound when the function was defined. And when the function was defined, i had a different value for each of the functions in your list!
It is a bit confusing that they've used the same name for the parameter variable as they did for the iterating variable. I suspect you could get the same result with greater readability with
def create_multipliers():
return [(lambda x, y=i: y*x) for i in range(5)]
In that case, each number in the range, will be assigned to the optional parameters of each lambda function:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
lambda x, i=0
lambda x, i=1
lambda x, i=2
lambda x, i=3
lambda x, i=4
So, you can call the functions now with one parameter (because they already have the default)
for f in create_multipliers():
print(f(3))
0
3
6
9
12
Or you can call the function and give the parameter you want, that's why is optional
for f in create_multipliers():
print(f(3,2))
6
6
6
6
6
There are examples where optional parameter are needed, such as recursion
For example, square in terms of square:
square = lambda n, m=0: 0 if n==m else n+square(n,m+1)
Look that the optional parameter there is used as accumulator
Id like to define a list of functions by a list of parameters, to actually compose a potential from a finite number of monopoles and dipoles.
Functions in python list, however, for some reason do not behave as expected (by me).
The following example:
def function(coefficients):
phi = []
i = 0
for y in coefficients:
f = lambda x: y*(x**i)
i += 1
phi.append(f)
print f(2)
return phi
> phi = function([1,2,3])
2
8
24
> k0 = phi[0]
> k1 = phi[1]
> k2 = phi[2]
> print k0(2), k1(2), k2(2)
24 24 24
Always the last function in the list is retrieved independent of which function is picked from the list.
Any ideas?
Thanks in advance.
The lambda function holds a reference to the variable y, because of the closure property. So, all the functions have the reference to the same object and they will get the last value of y during the invocation. To fix this,
f = lambda x,y=y,i=i: y*(x**i)
Now, we have created another parameter y and that has the default value y. It makes the function depend on a local reference now. So, even if the value of y changes in the loop, the lambda function no longer refers to that y.
Note: The same explanation is applicable to the variable i as well.
To make things very clear, I would recommend using different variable names
f = lambda x, z=y, j=i: z * (x ** j)
Note: Your original output was 2 8 24. That was because, when you invoke the function, i got incremented and I don't think that is what you really wanted. The actual output should have been 1 4 12.
I'm trying to return from a function a list of functions, each of which uses variables from the outside scope. This isn't working. Here's an example which demonstrates what's happening:
a = []
for i in range(10):
a.append(lambda x: x+i)
a[1](1) # returns 10, where it seems it should return 2
Why is this happening, and how can I get around it in python 2.7 ?
The i refers to the same variable each time, so i is 9 in all of the lambdas because that's the value of i at the end of the loop. Simplest workaround involves a default argument:
lambda x, i=i: x+i
This binds the value of the loop's i to a local variable i at the lambda's definition time.
Another workaround is to define a lambda that defines another lambda, and call the first lambda:
(lambda i: lambda x: x+i)(i)
This behavior makes a little more sense if you consider this:
def outerfunc():
def innerfunc():
return x+i
a = []
for i in range(10):
a.append(innerfunc)
return a
Here, innerfunc is defined once, so it makes intuitive sense that you are only working with a single function object, and you would not expect the loop to create ten different closures. With a lambda it doesn't look like the function is defined only once, it looks like you're defining it fresh each time through the loop, but in fact it is functionally the same as the the long version.
Because i isn't getting evaluated when you define the anonymous function (lambda expression) but when it's called. You can see this by adding del i before a[1](1): you'll get NameError: global name 'i' is not defined on the a[1](1) line.
You need to fix the value of i into the lambda expression every time, like so:
a = [lambda x, i=i: x+i for i in range(10)]
a[1](1) # returns 2
Another, more general solution - also without lambdas:
import operator
from functools import partial
a = []
for i in range(10):
a.append(partial(operator.add, i))
a[1][(1) # returns 2
The key aspect here is functools.partial.