61

Can someone explain the concrete reasons why BDFL choose to make Python lambdas single line?

This is good:

lambda x: x**x

This results in an error:

lambda x:
    x**x

I understand that making lambda multi-line would somehow "disturb" the normal indentation rules and would require adding more exceptions, but isn't that worth the benefits?

Look at JavaScript, for example. How can one live without those anonymous functions? They're indispensable. Don't Pythonistas want to get rid of having to name every multi-line function just to pass it as an argument?

4
  • 3
    Considering that you note the concrete reasons why Guido doesn't allow multi-expression lambdas and then dismiss them, I'm going to assume you're seeking validation rather than a real answer. Aug 7, 2011 at 18:13
  • 4
    Apart from saving seven characters, how is this any better than a def? It now has exactly the same visual structure.
    – detly
    Aug 8, 2011 at 1:28
  • 2
  • "require adding more exceptions" Nope, it would just require you, the user, not to misuse those "indentation rules" as law (they aren't rules, at least not from Python… your project's/company's coding style 'guidelines' is of course a whole different kind of beast). Feb 18 at 13:38

5 Answers 5

51

Guido van van Rossum answered it himself:

But such solutions often lack "Pythonicity" -- that elusive trait of a good Python feature. It's impossible to express Pythonicity as a hard constraint. Even the Zen of Python doesn't translate into a simple test of Pythonicity...

In the example above, it's easy to find the Achilles heel of the proposed solution: the double colon, while indeed syntactically unambiguous (one of the "puzzle constraints"), is completely arbitrary and doesn't resemble anything else in Python...

But I'm rejecting that too, because in the end (and this is where I admit to unintentionally misleading the submitter) 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.

http://www.artima.com/weblogs/viewpost.jsp?thread=147358

Basically, he says that although a solution is possible, it's not congruent with how Python is.

8
  • 2
    +1 thanks for the thread link -- but i would still appreciate multi-line lambdas -- they are invaluable -- look at JavaScript, PHP has them included also.
    – treecoder
    Aug 7, 2011 at 17:49
  • 3
    @greengit You can just use a nested def. It isn't the same as anonymous functions, but they're close enough.
    – jsternberg
    Aug 7, 2011 at 17:58
  • 2
    nested defs don't help when passing functions as arguments -- that's the number one reason why i'd like multi-line lambds
    – treecoder
    Aug 7, 2011 at 18:03
  • 13
    @greengit: You do know that you can pass the function in as an argument to another function? You can't write it inline, but there is no programming technique that is not available to you.
    – btilly
    Aug 7, 2011 at 19:56
  • 2
    @good_computer: The only difference between a lambda and a defed function is that the latter must have a name. Although I would like multi-expression lambda as well, it is not a must; it simply would make life a bit easier.
    – Siyuan Ren
    Aug 7, 2014 at 3:07
29

it's perfectly fine to do a multi line lambda in python: see

>>> f = lambda x: (
...   x**x)
>>> f
<function <lambda> at 0x7f95d8f85488>
>>> f(3)
27

the real lambda limitation is the fact that lambda must be a single expression; it can't contains keyword (like python2's print or return).

GvR choose to do so to limit the size of the lambda, as they normally are used as parameters. If you want a real function, use def

3
  • 1
    multi line is about the insert of the '\n' character :D python does not have multi statement lambda. You really want to use def. Think about it: you really need a callable as a parameter of your function? And the users of that function aren't allowed to pass your default callable? How can they pass it if you don't give it to them? Aug 7, 2011 at 18:14
  • btw, can you provide an example of your need of an anonimous function? Aug 7, 2011 at 18:19
  • 1
    Yeah, I find the limitation of a single expression really frustrating. True, that if they allow multi-expression lambdas people will most certainly start to abuse it but the other way around is too restrictive omho. Feb 21, 2016 at 0:05
12

I know this is super old, but putting here as a reference.

An alternative to using lambda could be to use a def in a non-conventional way. The goal is to pass a def to a function, which can be done in only one circumstance -- a decorator. Notice that with this implementation def result does not create a function, it creates the result of reduce(), which ends up being a dict.

Shameless plug: I do a lot of this here.

>>> xs = [('a', 1), ('b', 2), ('a', 3), ('b', 4)]
>>> foldl = lambda xs, initial: lambda f: reduce(f, xs, initial)
>>> @foldl(xs, {})
... def result(acc, (k, v)):
...     acc.setdefault(k, 0)
...     acc[k] += v
...     return acc
...
>>> result
{'a': 4, 'b': 6} 

Note that multi-statement lambdas can be done, but only with really, really ugly code. However, what is interesting is how scoping works with this implementation (note the multiple usage of the name variable and the shadowing of the message variable.

>>> from __future__ import print_function
>>> bind = lambda x, f=(lambda x: x): f(x)
>>> main = lambda: bind(
...     print('Enter your name.'), lambda _: bind(
...     raw_input('> '), lambda name: bind(
...     'Hello {}!'.format(name), lambda message: bind(
...     print(message), lambda _: bind(
...     'Bye {}!'.format(name), lambda message: bind(
...     print(message)
... ))))))
>>> main()
Enter your name.
> foo
Hello foo!
Bye foo!
2
  • +1 for a monadic approach Nov 16, 2013 at 13:54
  • Monads are also called thenables or future/promises or even callbacks in JavaScript BTW.
    – aoeu256
    Sep 11, 2019 at 22:20
4

Hacking together a multi-statement lambda isn't quite as bad as pyrospade makes out: sure we could compose a bunch of monadic functions using bind, like in Haskell, but since we're in the impure world of Python, we might as well use side-effects to achieve the same thing.

I cover a few ways to do this on my blog.

For example, Python guarantees to evaluate the elements of a tuple in order, so we can use , much like an imperative ;. We can replace many statements, like print, with expressions, like sys.stdout.write.

Hence the following are equivalent:

def print_in_tag_def(tag, text):
    print "<" + tag + ">"
    print text
    print "</" + tag + ">"

import sys
print_ = sys.stdout.write
print_in_tag_lambda = lambda tag, text: (print_("<" + tag + ">"),
                                         print_(text),
                                         print_("</" + tag + ">"),
                                         None)[-1]

Note that I've added a None at the end, and extracted it using [-1]; this sets the return value explicitly. We don't have to do this, but without it we'd get a funky (None, None, None) return value, which we may or may not care about.

So we can sequence IO actions. What about local variables?

Python's = forms an statement, so we need to find an equivalent expression. One way is to mutate the contents of datastructure, passed in as an argument. For example:

def stateful_def():
    foo = 10
    bar = foo * foo
    foo = 2
    return foo + bar

stateful_lambda = (lambda state: lambda *_: (state.setdefault('foo', 10),
                                             state.setdefault('bar', state.get('foo') * state.get('foo')),
                                             state.pop('foo'),
                                             state.setdefault('foo', 2),
                                             state.get('foo') + state.get('bar'))[-1])({})

There are few tricks being used in stateful_lambda:

  • The *_ argument allows our lambda to take any number of arguments. Since this allows zero arguments, we recover the calling convention of stateful_def.
    • Calling an argument _ is just a convention which says "I'm not going to use this variable"
  • We have one ("wrapper") function returning another ("main") function: lambda state: lambda *_: ...
    • Thanks to lexical scope, the argument of the first function will be in-scope for the second function
    • Accepting some arguments now and returning another function to accept the rest later is known as currying
  • We immediately call the "wrapper" function, passing it an empty dictionary: (lambda state: ...)({})
    • This lets us assign a variable state to a value {} without using an assignment statement (eg. state = {})
  • We treat keys and values in state as variable names and bound values
    • This is less cumbersome than using immediately-called lambdas
    • This allows us to mutate the values of variables
    • We use state.setdefault(a, b) instead of a = b and state.get(a) instead of a
  • We use a tuple to chain together our side-effects, like before
  • We use [-1] to extract the last value, which acts like a return statement

Of course this is pretty cumbersome, but we can make a nicer API with helper functions:

# Keeps arguments and values close together for immediately-called functions
callWith = lambda x, f: f(x)

# Returns the `get` and `setdefault` methods of a new dictionary
mkEnv = lambda *_: callWith({},
                            lambda d: (d.get,
                                       lambda k, v: (d.pop(k), d.setdefault(k, v))))

# A helper for providing a function with a fresh `get` and `setdefault`
inEnv = lambda f: callWith(mkEnv(), f)

# Delays the execution of a function
delay = lambda f x: lambda *_: f(x)

# Uses `get` and `set`(default) to mutate values
stateful_lambda = delay(inEnv, lambda get, set: (set('foo', 10),
                                                 set('bar', get('foo') * get('foo')),
                                                 set('foo', 2),
                                                 get('foo') + get('bar'))[-1])
2
  • are you kidding, this looks like a nightmare lol Sep 5, 2018 at 19:56
  • 1
    @AlexanderMills Heh, this wasn't intended as a real-world example, more of a refutation of pyrospade's lambdas-in-lambdas-in-lambdas approach, to show that things aren't that bad. In fact, this could be simplified much further now that we have python.org/dev/peps/pep-0572
    – Warbo
    Sep 7, 2018 at 18:39
1

I though i could contribute, use a line breaker:

x = lambda x,y: x-y if x<y \ 
                     else y-x if y<x \
                     else 0

Don't forget the very nice thing that python is able to write oneliners , as in example:

a=b=0; c=b+a; d = a+b**2 #etc etc

And the lambda is very powerful, but it is not meant for substitution of 1 whole function, i mean you could hack it like (borrowing example from colleague above) :

makeTag = lambda tagName: "<{}>".format(tagName)
closeTag = lambda tagName: makeTag("/"+str(tagName))
openTag = lambda tagName: makeTag(tagName)
writeHMTLline = lambda tag,content: ""+opetTag(tag)+str(content)+closeTag(tag)

But do you really want to do it like this ? It is mostly unreadable after some time, it is like getting to the beginning of the rope starting with unraveled end. unraveled rope

Lambdas are ment as one-only functions, in map,filter and reduce functions in Functional Oriented Programing ( among other things ). For example geting character values of values that are integers and divisible by 2

chrDev2 = lambda INT: chr(INT) if isinstance(INT,int) and INT%2==0 else INT
someStringList = map( chrDev2, range(30) )
>>> ['\x00', 1, '\x02', 3, '\x04', 5, '\x06', 7, '\x08', 9, '\n', 11, '\x0c', 13, '\x0e', 15, '\x10', 17, '\x12', 19, '\x14', 21, '\x16', 23, '\x18', 25, '\x1a', 27, '\x1c', 29]

You could use it as function expresions function by deifning complex function ( or more and several lambdas , and putting it inside another lambda:

def someAnon(*args): return sum(list(args))
defAnon = lambda list: [ x*someAnon(*list) for x in list]

but Python has function expresions support in another way: -lets say you have some function called superAwesomeFunction and that function can do some super awesome stuff, you can assign it to a variable by not calling it, like this:

SAF = superAwesomeFunction # there is no () at the end, 

So now when you call SAF you will call superAwesomeFunction or method. If you search trough your Lib folder you can find that most of python __builtin__ modules are written that way. This is done because sometimes you will need some functions that do specific task that is not necessary enough to be usable by user but it is necessary for several function. So then you have a choice you can not have 2 functions with name "superAwesomeFunction" , you can have "superAwesomeFunctionDoingBasicStuf" and "realSuperAwesomeFunction" and than just put the "realSuperAwesomeFunction" in "superAwesomeFunction" variable and you are done.

You can find the location of imported modules by entering in console importedModule.__file__ ( real example import os;os.__file__ ) , and just follow that directory to file called importedModule.py and open it in editor and find how you can maximize your own "knowledge".

I hope this helps you and maybe other colleagues in trouble.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.