Python closures and cells (closed-over values) - python

What is the Python mechanism that makes it so that
[lambda: x for x in range(5)][2]()
is 4?
What is the usual trick for binding a copy of x to each lamba expression so that the above expression will equal 2?
My final solution:
for template, model in zip(model_templates, model_classes):
def create_known_parameters(known_parms):
return lambda self: [getattr(self, p.name)
for p in known_parms]
model.known_parameters = create_known_parameters(template.known_parms)

>>> [lambda x=x: x for x in range(5)][2]()
2

I usually use functools.partial:
[ partial(lambda x: x, x) for x in range(5) ]
Or, of course, you can do it yourself:
[ (lambda x: (lambda: x))(x) for x in range(5) ]

Since no one's answered the "what is the mechanism" part, and this surprised me when I first read it, here's a go:
This:
ls = [lambda: x for x in range(5)]
Is a bit like this:
ls = []
x = 0
ls.append(lambda: x)
x = 1
ls.append(lambda: x)
x = 2
ls.append(lambda: x)
x = 3
ls.append(lambda: x)
x = 4
ls.append(lambda: x)
Each of those lambdas has its own scope, but none of those scopes contain an x. So they're all going to be reading the value of x by looking in an outer scope, so of course they must all be referring to the same object. By the time any of them are called, the loop is done and that object is the integer 4.
So even though these lambdas look like functions involving only immutable values, they can still be affected by side effects, because they depend on the bindings in an outer scope, and that scope can change.
You could of course further change what these lambdas return by rebinding x, or make them throw an error by unbinding it. In the list comprehension version though, the x is only bound in a private scope inside the list comprehension, so you can't mess with it (as easily).
The solution is of course to arrange things so that each lambda has an x in its local scope (or at least some outer scope that is not shared between the lambdas), so that they can all refer to different objects. Ways to do that have been shown in the other answers.

Related

Why does the UnboundLocalError occur on the second variable of the flat comprehension?

I answered a question here: comprehension list in python2 works fine but i get an error in python3
OP's error was using the same variables for max range and indices:
x = 12
y = 10
z = 12
n = 100
ret_list = [ (x,y,z) for x in range(x+1) for y in range(y+1) for z in range(z+1) if x+y+z!=n ]
This is a Python-3 error only, and related to the scopes that were added to the comprehension to avoid the variables defined here "leaking". Changing the variable names fixes that.
The error is:
UnboundLocalError: local variable 'y' referenced before assignment
because outer, global y is shadowed by the local scope.
My question is: why do I get the error on y and not on z or x ?
EDIT: If I remove the loop on x, the error moves to z:
>> ret_list = [ (x,y,z) for y in range(y+1) for z in range(z+1) if x+y+z!=n ]
UnboundLocalError: local variable 'z' referenced before assignment
If I just do one loop:
ret_list = [ (x,y,z) for y in range(y+1) if x+y+z!=n ]
it works. So I'm suspecting that the first range function is evaluated before all the other expressions, which leaves the value of x intact. But the exact reason is still to be found. Using Python 3.4.3.
This behaviour is (implicitly) described in the reference documentation (emphasis mine).
However, aside from the iterable expression in the leftmost for clause, the comprehension is executed in a separate implicitly nested scope. This ensures that names assigned to in the target list don’t “leak” into the enclosing scope.
The iterable expression in the leftmost for clause is evaluated directly in the enclosing scope and then passed as an argument to the implictly [sic] nested scope. Subsequent for clauses and any filter condition in the leftmost for clause cannot be evaluated in the enclosing scope as they may depend on the values obtained from the leftmost iterable. For example: [x*y for x in range(10) for y in range(x, x+10)].
This means that:
list_ = [(x, y) for x in range(x) for y in range(y)]
equivalent to:
def f(iter_):
for x in iter_:
for y in range(y):
yield x, y
list_ = list(f(iter(range(x))))
As the name x in for the leftmost iterable is read in the enclosing scope as opposed to the nested scope then there is no name conflict between these two uses of x. The same is not true for y, which is why it is where the UnboundLocalError occurs.
As to why this happens: a list comprehension is more-or-less syntactic sugar for list(<generator expression>), so it's going to be using the same code path as a generator expression (or at least behave in the same way). Generator expressions evaluate the iterable expression in the leftmost for clause to make error handling when the generator expression somewhat saner. Consider the following code:
y = None # line 1
gen = (x + 1 for x in range(y + 1)) # line 2
item = next(gen) # line 3
y is clearly the wrong type and so the addition will raise a TypeError. By evaluating range(y + 1) immediately that type error is raised on line 2 rather than line 3. Thus, it is easier to diagnose where and why the problem occurred. Had it occurred on line 3 then you might mistakenly assume that it was the x + 1 statement that caused the error.
There is a bug report here that mentions this behaviour. It was resolved as "not a bug" for reason that it is desirable that list comprehensions and generator expressions have the same behaviour.

Dictionary comprehension with lambda functions gives wrong results

I tried the following code in Python 3.5.1:
>>> f = {x: (lambda y: x) for x in range(10)}
>>> f[5](3)
9
It's obvious that this should return 5. I don't understand where the other value comes from, and I wasn't able to find anything.
It seems like it's something related to reference - it always returns the answer of f[9], which is the last function assigned.
What's the error here, and how should this be done so that it works properly?
Python scoping is lexical. A closure will refer to the name and scope of the variable, not the actual object/value of the variable.
What happens is that each lambda is capturing the variable x not the value of x.
At the end of the loop the variable x is bound to 9, therefore every lambda will refer to this x whose value is 9.
Why #ChrisP's answer works:
make_func forces the value of x to be evaluated (as it is passed
into a function). Thus, the lambda is made with value of x currently
and we avoid the above scoping issue.
def make_func(x):
return lambda y: x
f = {x: make_func(x) for x in range(10)}
The following should work:
def make_func(x):
return lambda y: x
f = {x: make_func(x) for x in range(10)}
The x in your code ends up referring to the last x value, which is 9, but in mine it refers to the x in the function scope.

Lambdas are restricted to a single expression! Why? [duplicate]

I've heard it said that multiline lambdas can't be added in Python because they would clash syntactically with the other syntax constructs in Python. I was thinking about this on the bus today and realized I couldn't think of a single Python construct that multiline lambdas clash with. Given that I know the language pretty well, this surprised me.
Now, I'm sure Guido had a reason for not including multiline lambdas in the language, but out of curiosity: what's a situation where including a multiline lambda would be ambiguous? Is what I've heard true, or is there some other reason that Python doesn't allow multiline lambdas?
Guido van Rossum (the inventor of Python) answers this exact question himself in an old blog post.
Basically, he admits that it's theoretically possible, but that any proposed solution would be un-Pythonic:
"But the complexity of any proposed solution for this puzzle is immense, to me: it requires the parser (or more precisely, the lexer) to be able to switch back and forth between indent-sensitive and indent-insensitive modes, keeping a stack of previous modes and indentation level. Technically that can all be solved (there's already a stack of indentation levels that could be generalized). But none of that takes away my gut feeling that it is all an elaborate Rube Goldberg contraption."
Look at the following:
map(multilambda x:
y=x+1
return y
, [1,2,3])
Is this a lambda returning (y, [1,2,3]) (thus map only gets one parameter, resulting in an error)? Or does it return y? Or is it a syntax error, because the comma on the new line is misplaced? How would Python know what you want?
Within the parens, indentation doesn't matter to python, so you can't unambiguously work with multilines.
This is just a simple one, there's probably more examples.
This is generally very ugly (but sometimes the alternatives are even more ugly), so a workaround is to make a braces expression:
lambda: (
doFoo('abc'),
doBar(123),
doBaz())
It won't accept any assignments though, so you'll have to prepare data beforehand.
The place I found this useful is the PySide wrapper, where you sometimes have short callbacks. Writing additional member functions would be even more ugly. Normally you won't need this.
Example:
pushButtonShowDialog.clicked.connect(
lambda: (
field1.clear(),
spinBox1.setValue(0),
diag.show())
A couple of relevant links:
For a while, I was following the development of Reia, which was initially going to have Python's indentation based syntax with Ruby blocks too, all on top of Erlang. But, the designer wound up giving up on indentation sensitivity, and this post he wrote about that decision includes a discussion about problems he ran into with indentation + multi-line blocks, and an increased appreciation he gained for Guido's design issues/decisions:
http://www.unlimitednovelty.com/2009/03/indentation-sensitivity-post-mortem.html
Also, here's an interesting proposal for Ruby-style blocks in Python I ran across where Guido posts a response w/o actually shooting it down (not sure whether there has been any subsequent shoot down, though):
http://tav.espians.com/ruby-style-blocks-in-python.html
Let me present to you a glorious but terrifying hack:
import types
def _obj():
return lambda: None
def LET(bindings, body, env=None):
'''Introduce local bindings.
ex: LET(('a', 1,
'b', 2),
lambda o: [o.a, o.b])
gives: [1, 2]
Bindings down the chain can depend on
the ones above them through a lambda.
ex: LET(('a', 1,
'b', lambda o: o.a + 1),
lambda o: o.b)
gives: 2
'''
if len(bindings) == 0:
return body(env)
env = env or _obj()
k, v = bindings[:2]
if isinstance(v, types.FunctionType):
v = v(env)
setattr(env, k, v)
return LET(bindings[2:], body, env)
You can now use this LET form as such:
map(lambda x: LET(('y', x + 1,
'z', x - 1),
lambda o: o.y * o.z),
[1, 2, 3])
which gives: [0, 3, 8]
[Edit Edit] Since this question is somehow still active 12 years after being asked. I will continue the tradition of amending my answer every 4 years or so.
Firstly, the question was how does multi-line lambda clash with Python. The accepted answer shows how with a simple example. The highly rated answer I linked below some years ago answers the question of "Why is it not a part of Python"--this answer is perhaps more satisfying to those who believe that the existing examples of "clashing" are not enough to make multi-line lambda impossible to implement in Python.
In previous iterations of this answer I discussed how to implement multi-line lambda into Python as is. I've since removed that part, because it was a flurry of bad practices. You may see it in the edit history of this answer if you wish.
However the answer to "Why not?", being "because Rossum said so" can still be a source of frustration. So lets see if it could be engineered around the counter example given by user balpha:
map(lambda x:
y=x+1 # <-- this line defines the outmost indent level*
for i in range(12):
y+=12
return y
, [1,2,3])
#*By convention it is always one-indent past the 'l' in lambda
As for the return value we have that the following is non-permissible in python:
def f():
return 3
, [1,2,3]
So by the same logic, "[1,2,3]" should not be part of the return value. Let's try it this way instead:
map(lambda x:
y=x+1 # part of lambda block
for i in range(12): # part of lambda block
y+=12 # part of lambda block
return y, [1,2,3]) # part of lambda block
This one's trickier, but since the lambda block has a clearly defined beginning (the token 'lambda') yet no clear ending, I would argue anything that is on the same line as part of a lambda block is also part of the lambda block.
One might imagine some features that can identify closing parenthesis or even inference based on the number of tokens expected by the enclosing element. In general, the above expression does not seem totally impossible to parse, but it may be a bit of a challenge.
To simplify things, you could separate all characters not intended to be part of the block:
map(lambda x:
y=x+1 # part of lambda block
for i in range(12): # part of lambda block
y+=12 # part of lambda block
return y # part of lambda block
, [1,2,3]) # argument separator, second argument, and closing paren for map
Back to where we were but this time it is unambiguous, because the last line is behind the lowest indent-depth for the lambda block.
Single line lambda would be a special case (identified by the lack of an immediate newline after the color), that behaves the same as it does now.
This is not to say that it necessarily should be a part of Python--but it is a quick illustration that is perhaps is possible with some changes in the language.
[Edit] Read this answer. It explains why multi-line lambda is not a thing.
Simply put, it's unpythonic. From Guido van Rossum's blog post:
I find any solution unacceptable that embeds an indentation-based block in the middle of an expression. Since I find alternative syntax for statement grouping (e.g. braces or begin/end keywords) equally unacceptable, this pretty much makes a multi-line lambda an unsolvable puzzle.
I'm guilty of practicing this dirty hack in some of my projects which is bit simpler:
lambda args...:( expr1, expr2, expr3, ...,
exprN, returnExpr)[-1]
I hope you can find a way to stay pythonic but if you have to do it this less painful than using exec and manipulating globals.
Let me also throw in my two cents about different workarounds.
How is a simple one-line lambda different from a normal function? I can think only of lack of assignments, some loop-like constructs (for, while), try-except clauses... And that's it? We even have a ternary operator - cool! So, let's try to deal with each of these problems.
Assignments
Some guys here have rightly noted that we should take a look at lisp's let form, which allows local bindings. Actually, all the non state-changing assignments can be performed only with let. But every lisp programmer knows that let form is absolutely equivalent to call to a lambda function! This means that
(let ([x_ x] [y_ y])
(do-sth-with-x-&-y x_ y_))
is the same as
((lambda (x_ y_)
(do-sth-with-x-&-y x_ y_)) x y)
So lambdas are more than enough! Whenever we want to make a new assignment we just add another lambda and call it. Consider this example:
def f(x):
y = f1(x)
z = f2(x, y)
return y,z
A lambda version looks like:
f = lambda x: (lambda y: (y, f2(x,y)))(f1(x))
You can even make the let function, if you don't like the data being written after actions on the data. And you can even curry it (just for the sake of more parentheses :) )
let = curry(lambda args, f: f(*args))
f_lmb = lambda x: let((f1(x),), lambda y: (y, f2(x,y)))
# or:
f_lmb = lambda x: let((f1(x),))(lambda y: (y, f2(x,y)))
# even better alternative:
let = lambda *args: lambda f: f(*args)
f_lmb = lambda x: let(f1(x))(lambda y: (y, f2(x,y)))
So far so good. But what if we have to make reassignments, i.e. change state? Well, I think we can live absolutely happily without changing state as long as task in question doesn't concern loops.
Loops
While there's no direct lambda alternative for loops, I believe we can write quite generic function to fit our needs. Take a look at this fibonacci function:
def fib(n):
k = 0
fib_k, fib_k_plus_1 = 0, 1
while k < n:
k += 1
fib_k_plus_1, fib_k = fib_k_plus_1 + fib_k, fib_k_plus_1
return fib_k
Impossible in terms of lambdas, obviously. But after writing a little yet useful function we're done with that and similar cases:
def loop(first_state, condition, state_changer):
state = first_state
while condition(*state):
state = state_changer(*state)
return state
fib_lmb = lambda n:\
loop(
(0,0,1),
lambda k, fib_k, fib_k_plus_1:\
k < n,
lambda k, fib_k, fib_k_plus_1:\
(k+1, fib_k_plus_1, fib_k_plus_1 + fib_k))[1]
And of course, one should always consider using map, reduce and other higher-order functions if possible.
Try-except and other control structs
It seems like a general approach to this kind of problems is to make use of lazy evaluation, replacing code blocks with lambdas accepting no arguments:
def f(x):
try: return len(x)
except: return 0
# the same as:
def try_except_f(try_clause, except_clause):
try: return try_clause()
except: return except_clause()
f = lambda x: try_except_f(lambda: len(x), lambda: 0)
# f(-1) -> 0
# f([1,2,3]) -> 3
Of course, this is not a full alternative to try-except clause, but you can always make it more generic. Btw, with that approach you can even make if behave like function!
Summing up: it's only natural that everything mentioned feels kinda unnatural and not-so-pythonically-beautiful. Nonetheless - it works! And without any evals and other trics, so all the intellisense will work. I'm also not claiming that you shoud use this everywhere. Most often you'd better define an ordinary function. I only showed that nothing is impossible.
Let me try to tackle #balpha parsing problem. I would use parentheses around the multiline lamda. If there is no parentheses, the lambda definition is greedy. So the lambda in
map(lambda x:
y = x+1
z = x-1
y*z,
[1,2,3]))
returns a function that returns (y*z, [1,2,3])
But
map((lambda x:
y = x+1
z = x-1
y*z)
,[1,2,3]))
means
map(func, [1,2,3])
where func is the multiline lambda that return y*z. Does that work?
(For anyone still interested in the topic.)
Consider this (includes even usage of statements' return values in further statements within the "multiline" lambda, although it's ugly to the point of vomiting ;-)
>>> def foo(arg):
... result = arg * 2;
... print "foo(" + str(arg) + ") called: " + str(result);
... return result;
...
>>> f = lambda a, b, state=[]: [
... state.append(foo(a)),
... state.append(foo(b)),
... state.append(foo(state[0] + state[1])),
... state[-1]
... ][-1];
>>> f(1, 2);
foo(1) called: 2
foo(2) called: 4
foo(6) called: 12
12
Here's a more interesting implementation of multi line lambdas. It's not possible to achieve because of how python use indents as a way to structure code.
But luckily for us, indent formatting can be disabled using arrays and parenthesis.
As some already pointed out, you can write your code as such:
lambda args: (expr1, expr2,... exprN)
In theory if you're guaranteed to have evaluation from left to right it would work but you still lose values being passed from one expression to an other.
One way to achieve that which is a bit more verbose is to have
lambda args: [lambda1, lambda2, ..., lambdaN]
Where each lambda receives arguments from the previous one.
def let(*funcs):
def wrap(args):
result = args
for func in funcs:
if not isinstance(result, tuple):
result = (result,)
result = func(*result)
return result
return wrap
This method let you write something that is a bit lisp/scheme like.
So you can write things like this:
let(lambda x, y: x+y)((1, 2))
A more complex method could be use to compute the hypotenuse
lst = [(1,2), (2,3)]
result = map(let(
lambda x, y: (x**2, y**2),
lambda x, y: (x + y) ** (1/2)
), lst)
This will return a list of scalar numbers so it can be used to reduce multiple values to one.
Having that many lambda is certainly not going to be very efficient but if you're constrained it can be a good way to get something done quickly then rewrite it as an actual function later.
In Python 3.8/3.9 there is Assignment Expression, so it could be used in lambda, greatly
expanding functionality
E.g., code
#%%
x = 1
y = 2
q = list(map(lambda t: (
tx := t*x,
ty := t*y,
tx+ty
)[-1], [1, 2, 3]))
print(q)
will print [3, 6, 9]
After Python3.8, there is another method for local binding
lambda x: (
y := x + 1,
y ** 2
)[-1]
For Loop
lambda x: (
y := x ** 2,
[y := y + x for _ in range(10)],
y
)[-1]
If Branch
lambda x: (
y := x ** 2,
x > 5 and [y := y + x for _ in range(10)],
y
)[-1]
Or
lambda x: (
y := x ** 2,
[y := y + x for _ in range(10)] if x > 5 else None,
y
)[-1]
While Loop
import itertools as it
lambda x: (
l := dict(y = x ** 2),
cond := lambda: l['y'] < 100,
body := lambda: l.update(y = l['y'] + x),
*it.takewhile(lambda _: cond() and (body(), True)[-1], it.count()),
l['y']
)[-1]
Or
import itertools as it
from types import SimpleNamespace as ns
lambda x: (
l := ns(y = x ** 2),
cond := lambda: l.y < 100,
body := lambda: vars(l).update(y = l.y + x),
*it.takewhile(lambda _: cond() and (body(), True)[-1], it.count()),
l.y
)[-1]
Or
import itertools as it
lambda x: (
y := x ** 2,
*it.takewhile(lambda t: t[0],
((
pred := y < 100,
pred and (y := y + x))
for _ in it.count())),
y
)[-1]
On the subject of ugly hacks, you can always use a combination of exec and a regular function to define a multiline function like this:
f = exec('''
def mlambda(x, y):
d = y - x
return d * d
''', globals()) or mlambda
You can wrap this into a function like:
def mlambda(signature, *lines):
exec_vars = {}
exec('def mlambda' + signature + ':\n' + '\n'.join('\t' + line for line in lines), exec_vars)
return exec_vars['mlambda']
f = mlambda('(x, y)',
'd = y - x',
'return d * d')
I know it is an old question, but for the record here is a kind of a solution to the problem of multiline lambda problem in which the result of one call is consumed by another call.
I hope it is not super hacky, since it is based only on standard library functions and uses no dunder methods.
Below is a simple example in which we start with x = 3 and then in the first line we add 1 and then in the second line we add 2 and get 6 as the output.
from functools import reduce
reduce(lambda data, func: func(data), [
lambda x: x + 1,
lambda x: x + 2
], 3)
## Output: 6
I was just playing a bit to try to make a dict comprehension with reduce, and come up with this one liner hack:
In [1]: from functools import reduce
In [2]: reduce(lambda d, i: (i[0] < 7 and d.__setitem__(*i[::-1]), d)[-1], [{}, *{1:2, 3:4, 5:6, 7:8}.items()])
Out[3]: {2: 1, 4: 3, 6: 5}
I was just trying to do the same as what was done in this Javascript dict comprehension: https://stackoverflow.com/a/11068265
You can simply use slash (\) if you have multiple lines for your lambda function
Example:
mx = lambda x, y: x if x > y \
else y
print(mx(30, 20))
Output: 30
I am starting with python but coming from Javascript the most obvious way is extract the expression as a function....
Contrived example, multiply expression (x*2) is extracted as function and therefore I can use multiline:
def multiply(x):
print('I am other line')
return x*2
r = map(lambda x : multiply(x), [1, 2, 3, 4])
print(list(r))
https://repl.it/#datracka/python-lambda-function
Maybe it does not answer exactly the question if that was how to do multiline in the lambda expression itself, but in case somebody gets this thread looking how to debug the expression (like me) I think it will help
One safe method to pass any number of variables between lambda items:
print((lambda: [
locals().__setitem__("a", 1),
locals().__setitem__("b", 2),
locals().__setitem__("c", 3),
locals().get("a") + locals().get("b") + locals().get("c")
])()[-1])
Output: 6
because a lambda function is supposed to be one-lined, as its the simplest form of a function, an entrance, then return

Python functions within lists

So today in computer science I asked about using a function as a variable. For example, I can create a function, such as returnMe(i) and make an array that will be used to call it. Like h = [help,returnMe] and then I can say h1 and it would call returnMe("Bob"). Sorry I was a little excited about this. My question is is there a way of calling like h.append(def function) and define a function that only exists in the array?
EDIT:
Here Is some code that I wrote with this!
So I just finished an awesome FizzBuzz with this solution thank you so much again! Here's that code as an example:
funct = []
s = ""
def newFunct(str, num):
return (lambda x: str if(x%num==0) else "")
funct.append(newFunct("Fizz",3))
funct.append(newFunct("Buzz",5))
for x in range(1,101):
for oper in funct:
s += oper(x)
s += ":"+str(x)+"\n"
print s
You can create anonymous functions using the lambda keyword.
def func(x,keyword='bar'):
return (x,keyword)
is roughly equivalent to:
func = lambda x,keyword='bar':(x,keyword)
So, if you want to create a list with functions in it:
my_list = [lambda x:x**2,lambda x:x**3]
print my_list[0](2) #4
print my_list[1](2) #8
Not really in Python. As mgilson shows, you can do this with trivial functions, but they can only contain expressions, not statements, so are very limited (you can't assign to a variable, for example).
This is of course supported in other languages: in Javascript, for example, creating substantial anonymous functions and passing them around is a very idiomatic thing to do.
You can create the functions in the original scope, assign them to the array and then delete them from their original scope. Thus, you can indeed call them from the array but not as a local variable. I am not sure if this meets your requirements.
#! /usr/bin/python3.2
def a (x): print (x * 2)
def b (x): print (x ** 2)
l = [a, b]
del a
del b
l [0] (3) #works
l [1] (3) #works
a (3) #fails epicly
You can create a list of lambda functions to increment by every number from 0 to 9 like so:
increment = [(lambda arg: (lambda x: arg + x))(i) for i in range(10)]
increment[0](1) #returns 1
increment[9](10) #returns 19
Side Note:
I think it's also important to note that this (function pointers not lambdas) is somewhat like how python holds methods in most classes, except instead of a list, it's a dictionary with function names pointing to the functions. In many but not all cases instance.func(args) is equivalent to instance.__dict__['func'](args) or type(class).__dict__['func'](args)

lambda returns lambda in python

Very rarely I'll come across some code in python that uses an anonymous function which returns an anonymous function...?
Unfortunately I can't find an example on hand, but it usually takes the form like this:
g = lambda x,c: x**c lambda c: c+1
Why would someone do this? Maybe you can give an example that makes sense (I'm not sure the one I made makes any sense).
Edit: Here's an example:
swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])),
f(y,a[x][0]),f(x,a[x][1])))()
You could use such a construct to do currying:
curry = lambda f, a: lambda x: f(a, x)
You might use it like:
>>> add = lambda x, y: x + y
>>> add5 = curry(add, 5)
>>> add5(3)
8
swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])),
f(y,a[x][0]),f(x,a[x][1])))()
See the () at the end? The inner lambda isn't returned, its called.
The function does the equivalent of
def swap(a, x, y):
a[x] = (a[x], a[y])
a[y] = a[x][0]
a[x] = a[x][1]
But let's suppose that we want to do this in a lambda. We cannot use assignments in a lambda. However, we can call __setitem__ for the same effect.
def swap(a, x, y):
a.__setitem__(x, (a[x], a[y]))
a.__setitem__(y, a[x][0])
a.__setitem__(x, a[x][1])
But for a lambda, we can only have one expression. But since these are function calls we can wrap them up in a tuple
def swap(a, x, y):
(a.__setitem__(x, (a[x], a[y])),
a.__setitem__(y, a[x][0]),
a.__setitem__(x, a[x][1]))
However, all those __setitem__'s are getting me down, so let's factor them out:
def swap(a, x, y):
f = a.__setitem__
(f(x, (a[x], a[y])),
f(y, a[x][0]),
f(x, a[x][1]))
Dagnamit, I can't get away with adding another assignment! I know let's abuse default parameters.
def swap(a, x, y):
def inner(f = a.__setitem__):
(f(x, (a[x], a[y])),
f(y, a[x][0]),
f(x, a[x][1]))
inner()
Ok let's switch over to lambdas:
swap = lambda a, x, y: lambda f = a.__setitem__: (f(x, (a[x], a[y])), f(y, a[x][0]), f(x, a[x][1]))()
Which brings us back to the original expression (plus/minus typos)
All of this leads back to the question: Why?
The function should have been implemented as
def swap(a, x, y):
a[x],a[y] = a[y],a[x]
The original author went way out of his way to use a lambda rather then a function. It could be that he doesn't like nested function for some reason. I don't know. All I'll say is its bad code. (unless there is a mysterious justification for it.)
It can be useful for temporary placeholders. Suppose you have a decorator factory:
#call_logger(log_arguments=True, log_return=False)
def f(a, b):
pass
You can temporarily replace it with
call_logger = lambda *a, **kw: lambda f: f
It can also be useful if it indirectly returns a lambda:
import collections
collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(int)))
It's also useful for creating callable factories in the Python console.
And just because something is possible doesn't mean that you have to use it.
I did something like this just the other day to disable a test method in a unittest suite.
disable = lambda fn : lambda *args, **kwargs: None
#disable
test_method(self):
... test code that I wanted to disable ...
Easy to re-enable it later.
This can be used to pull out some common repetitive code (there are of course other ways to achieve this in python).
Maybe you're writing a a logger, and you need to prepend the level to the log string. You might write something like:
import sys
prefixer = lambda prefix: lambda message: sys.stderr.write(prefix + ":" + message + "\n")
log_error = prefixer("ERROR")
log_warning = prefixer("WARNING")
log_info = prefixer("INFO")
log_debug = prefixer("DEBUG")
log_info("An informative message")
log_error("Oh no, a fatal problem")
This program prints out
INFO:An informative message
ERROR:Oh no, a fatal problem
It is most oftenly - at least in code I come accross and that I myself write - used to "freeze" a variable with the value it has at the point the lambda function is created. Otherwise, nonlocals variable reference a variable in the scope they exist, which can lead to undesied results sometimes.
For example, if I want to create a list of ten functions, each one being a multiplier for a scalar from 0 to 9. One might be tempted to write it like this:
>>> a = [(lambda j: i * j) for i in range(10)]
>>> a[9](10)
90
Whoever, if you want to use any of the other factoried functions you get the same result:
>>> a[1](10)
90
That is because the "i" variable inside the lambda is not resolved when the lambda is created. Rather, Python keeps a reference to the "i" in the "for" statement - on the scope it was created (this reference is kept in the lambda function closure). When the lambda is executed, the variable is evaluated, and its value is the final one it had in that scope.
When one uses two nested lambdas like this:
>>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)]
The "i" variable is evaluated durint the execution of the "for" loop. Itś value is passed to "k" - and "k" is used as the non-local variable in the multiplier function we are factoring out. For each value of i, there will be a different instance of the enclosing lambda function, and a different value for the "k" variable.
So, it is possible to achieve the original intent :
>>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)]
>>> a[1](10)
10
>>> a[9](10)
90
>>>
It can be used to achieve a more continuation/trampolining style of programming,
See Continuation-passing style
Basically, with this you can modify functions instead of values
One example I stumbled with recently: To compute approximate derivatives (as functions) and use it as an input function in another place.
dx = 1/10**6
ddx = lambda f: lambda x: (f(x + dx) - f(x))/dx
f = lambda x: foo(x)
newton_method(func=ddx(f), x0=1, n=10)

Categories