Related
During a tutorial I stumbled upon the following example.
I get the general purpose and mechanism of functions. They get parameters such as "a", "b" and "c" (example below).
But how come that we can "link" the function to an object f that itself can contain 0 as parameters that will then be computed by our lambda expression?
def build_quadratic_function(a,b,c):
return lambda x: a*x**2 + b*x+c
f = build_quadratic_function(2,3,-5)
f(0)
yields:
-5
In layman words, how does the function "know" that 0 must be read by the lambda expression that is contained in the function?
Can somebody explain the mechanism behind it?
Thank you!
def build_quadratic_function(a,b,c):
return lambda x: a*x**2 + b*x + c
is (in all important aspects) equivalent to
def build_quadratic_function(a,b,c):
def func(x):
return a*x**2 + b*x + c
return func
In both cases, the inner function, be it an anonymous one or not, is holding onto the variables in the enclosing scope. You have discovered so called closures.
>>> import inspect
>>> f = build_quadratic_function(2, 3, -5)
>>> inspect.getclosurevars(f)
ClosureVars(nonlocals={'a': 2, 'b': 3, 'c': -5}, globals={}, builtins={}, unbound=set())
A very similar example can be found in the documentation.
Lambdas are small anonymous functions. They can be used wherever function objects are required. They are syntactically restricted to a single expression. Semantically, they are just syntactic sugar for a normal function definition. Like nested function definitions, lambda functions can reference variables from the containing scope.
Therefore if you define a custom function that contains a lambda, and then fix its parameters, it's essentially the same as defining a lambda function and then passing the expression.
For the sake of your example:
def build_quadratic_function(a,b,c):
return lambda x: a*x**2 + b*x+c
f = build_quadratic_function(2,3,-5)
Would create the same output as:
f = lambda x: 2*x**2 + 3*x - 5
In either case, when you call f(0) then the expression gets evaluated with value 0 returning -5.
2*0**2 + 3*0 - 5 = - 5
The improvement using a custom function over the simple definition of the lambda itself is you can modify the a, b and c parameters.
This isn't a lambda specific thing. Its a "closure" and can be done with a regular function also. In fact, a lambda is just an anonymous function. Its it restricted to implementing an expression instead of full python statements, but that's only the case because of python parsing issues. So, this is the same thing
def build_quadratic_function(a,b,c):
def inner(x):
return a*x**2 + b*x+c
return inner
inner uses variables from the enclosing function. When build_quadratic_function returns inner, the current objects in a, b and c are bound to inner. Later, when inner(someval) is called, those bound objects to a, b and c are used. x, which is a parameter to inner needs to be supplied on each call.
You can get the inner function once and use it many times with the same values.
func = build_quadratic_function(1,2,3)
for i in range(10):
print(func(i))
A lambda function is a small anonymous function. (function with no name)
f = build_quadratic_function(2,3,-5)
Till this point, f is equal to the return value of build_quadratic_function, which is another function(lambda in this case)!
f(0) calls the lambda which is waiting
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
I get this pep8 warning whenever I use lambda expressions. Are lambda expressions not recommended? If not why?
The recommendation in PEP-8 you are running into is:
Always use a def statement instead of an assignment statement that
binds a lambda expression directly to a name.
Yes:
def f(x): return 2*x
No:
f = lambda x: 2*x
The first form means that the name of the resulting
function object is specifically 'f' instead of the generic '<lambda>'.
This is more useful for tracebacks and string representations in
general. The use of the assignment statement eliminates the sole
benefit a lambda expression can offer over an explicit def statement
(i.e. that it can be embedded inside a larger expression)
Assigning lambdas to names basically just duplicates the functionality of def - and in general, it's best to do something a single way to avoid confusion and increase clarity.
The legitimate use case for lambda is where you want to use a function without assigning it, e.g:
sorted(players, key=lambda player: player.rank)
In general, the main argument against doing this is that def statements will result in more lines of code. My main response to that would be: yes, and that is fine. Unless you are code golfing, minimising the number of lines isn't something you should be doing: go for clear over short.
Here is the story, I had a simple lambda function which I was using twice.
a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)
This is just for the representation, I have faced couple of different versions of this.
Now, to keep things DRY, I start to reuse this common lambda.
f = lambda x : x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
At this point my code quality checker complains about lambda being a named function so I convert it into a function.
def f(x):
return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Now the checker complains that a function has to be bounded by one blank line before and after.
def f(x):
return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Here we have now 6 lines of code instead of original 2 lines with no increase in readability and no increase in being pythonic. At this point the code checker complains about the function not having docstrings.
In my opinion this rule better be avoided and broken when it makes sense, use your judgement.
Lattyware is absolutely right: Basically PEP-8 wants you to avoid things like
f = lambda x: 2 * x
and instead use
def f(x):
return 2 * x
However, as addressed in a recent bugreport (Aug 2014), statements such as the following are now compliant:
a.f = lambda x: 2 * x
a["f"] = lambda x: 2 * x
Since my PEP-8 checker doesn't implement this correctly yet, I turned off E731 for the time being.
I also encountered a situation in which it was even impossible to use a def(ined) function.
class SomeClass(object):
# pep-8 does not allow this
f = lambda x: x + 1 # NOQA
def not_reachable(self, x):
return x + 1
#staticmethod
def also_not_reachable(x):
return x + 1
#classmethod
def also_not_reachable(cls, x):
return x + 1
some_mapping = {
'object1': {'name': "Object 1", 'func': f},
'object2': {'name': "Object 2", 'func': some_other_func},
}
In this case, I really wanted to make a mapping which belonged to the class. Some objects in the mapping needed the same function. It would be illogical to put the a named function outside of the class.
I have not found a way to refer to a method (staticmethod, classmethod or normal) from inside the class body. SomeClass does not exist yet when the code is run. So referring to it from the class isn't possible either.
This works for me in a class, remove lambda expression and use def instead, changing this...
def set_every(self, every: int = 1, time_unit: int = TimeUnit.Day):
every_func = lambda x: "*" if x == 1 else "*/" + str(x)
if TimeUnit.has_value(time_unit):
self.month_of_year = "*"
self.day_of_month = "*" if time_unit != TimeUnit.Day else every_func(every)
self.day_of_week = "*" if time_unit != TimeUnit.Week else every_func(every)
by this...
def set_every(self, every: int = 1, time_unit: int = TimeUnit.Day):
def every_func(x: int) -> str: return "*" if x == 1 else "*/" + str(x)
if TimeUnit.has_value(time_unit):
self.month_of_year = "*"
self.day_of_month = "*" if time_unit != TimeUnit.Day else every_func(every)
self.day_of_week = "*" if time_unit != TimeUnit.Week else every_func(every)
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
I'm trying to write a lambda-expression that calls itself, but i can't seem to find any syntax for that, or even if it's possible.
Essentially what I wanted to transfer the following function into the following lambda expression: (I realize it's a silly application, it just adds, but I'm exploring what I can do with lambda-expressions in python)
def add(a, b):
if a <= 0:
return b
else:
return 1 + add(a - 1, b)
add = lambda a, b: [1 + add(a-1, b), b][a <= 0]
but calling the lambda form of add results in a runtime error because the maximum recursion depth is reached. Is it even possible to do this in python? Or am I just making some stupid mistake? Oh, I'm using python3.0, but I don't think that should matter?
Maybe you need a Y combinator?
Edit - make that a Z combinator (I hadn't realized that Y combinators are more for call-by-name)
Using the definition of the Z combinator from Wikipedia
>>> Z = lambda f: (lambda x: f(lambda *args: x(x)(*args)))(lambda x: f(lambda *args: x(x)(*args)))
Using this, you can then define add as a completely anonymous function (ie. no reference to its name in its definition)
>>> add = Z(lambda f: lambda a, b: b if a <= 0 else 1 + f(a - 1, b))
>>> add(1, 1)
2
>>> add(1, 5)
6
Perhaps you should try the Z combinator, where this example is from:
>>> Z = lambda f: (lambda x: f(lambda *args: x(x)(*args)))(lambda x: f(lambda *args: x(x)(*args)))
>>> fact = lambda f: lambda x: 1 if x == 0 else x * f(x-1)
>>> Z(fact)(5)
120
First of all recursive lambda expressions are completely unnecessary. As you yourself point out, for the lambda expression to call itself, it needs to have a name. But lambda expressions is nothing else than anonymous functions. So if you give the lambda expression a name, it's no longer a lambda expression, but a function.
Hence, using a lambda expression is useless, and will only confuse people. So create it with a def instead.
But yes, as you yourself discovered, lambda expressions can be recursive. Your own example is. It's in fact so fantastically recursive that you exceed the maximum recursion depth. So it's recursive alright. Your problem is that you always call add in the expression, so the recursion never stops. Don't do that. Your expression can be expressed like this instead:
add = lambda a, b: a > 0 and (1 + add(a-1, b)) or b
Which takes care of that problem. However, your first def is the correct way of doing it.
add = lambda a, b: b if a <= 0 else 1 + add(a - 1, b)
You want the Y combinator, or some other fixed point combinator.
Here's an example implementation as a Python lambda expression:
Y = lambda g: (lambda f: g(lambda arg: f(f)(arg))) (lambda f: g(lambda arg: f(f)(arg)))
Use it like so:
factorial = Y(lambda f: (lambda num: num and num * f(num - 1) or 1))
That is, you pass into Y() a single-argument function (or lambda), which receives as its argument a recursive version of itself. So the function doesn't need to know its own name, since it gets a reference to itself instead.
Note that this does get tricky for your add() function because the Y combinator only supports passing a single argument. You can get more arguments by currying -- but I'll leave that as an exercise for the reader. :-)
a little late ... but I just found this gem # http://metapython.blogspot.com/2010/11/recursive-lambda-functions.html
def myself (*args, **kw):
caller_frame = currentframe(1)
code = caller_frame.f_code
return FunctionType(code, caller_frame.f_globals)(*args,**kw)
print "5! = "
print (lambda x:1 if n <= 1 else myself(n-1)*n)(5)