Learning Python - Mark Lutz [266]
>>> lower = (lambda x, y: x if x < y else y)
>>> lower('bb', 'aa')
'aa'
>>> lower('aa', 'bb')
'aa'
Furthermore, if you need to perform loops within a lambda, you can also embed things like map calls and list comprehension expressions (tools we met in earlier chapters and will revisit in this and the next chapter):
>>> import sys
>>> showall = lambda x: list(map(sys.stdout.write, x)) # Use list in 3.0
>>> t = showall(['spam\n', 'toast\n', 'eggs\n'])
spam
toast
eggs
>>> showall = lambda x: [sys.stdout.write(line) for line in x]
>>> t = showall(('bright\n', 'side\n', 'of\n', 'life\n'))
bright
side
of
life
Now that I’ve shown you these tricks, I am required by law to ask you to please only use them as a last resort. Without due care, they can lead to unreadable (a.k.a. obfuscated) Python code. In general, simple is better than complex, explicit is better than implicit, and full statements are better than arcane expressions. That’s why lambda is limited to expressions. If you have larger logic to code, use def; lambda is for small pieces of inline code. On the other hand, you may find these techniques useful in moderation.
Nested lambdas and Scopes
lambdas are the main beneficiaries of nested function scope lookup (the E in the LEGB scope rule we studied in Chapter 17). In the following, for example, the lambda appears inside a def—the typical case—and so can access the value that the name x had in the enclosing function’s scope at the time that the enclosing function was called:
>>> def action(x):
... return (lambda y: x + y) # Make and return function, remember x
...
>>> act = action(99)
>>> act
>>> act(2) # Call what action returned 101 What wasn’t illustrated in the prior discussion of nested function scopes is that a lambda also has access to the names in any enclosing lambda. This case is somewhat obscure, but imagine if we recoded the prior def with a lambda: >>> action = (lambda x: (lambda y: x + y)) >>> act = action(99) >>> act(3) 102 >>> ((lambda x: (lambda y: x + y))(99))(4) 103 Here, the nested lambda structure makes a function that makes a function when called. In both cases, the nested lambda’s code has access to the variable x in the enclosing lambda. This works, but it’s fairly convoluted code; in the interest of readability, nested lambdas are generally best avoided. * * * Why You Will Care: Callbacks import sys from tkinter import Button, mainloop # Tkinter in 2.6 x = Button( text ='Press me', command=(lambda:sys.stdout.write('Spam\n'))) x.pack() mainloop() Here, the callback handler is registered by passing a function generated with a lambda to the command keyword argument. The advantage of lambda over def here is that the code that handles a button press is right here, embedded in the button-creation call. In effect, the lambda defers execution of the handler until the event occurs: the write call happens on button presses, not when the button is created. Because the nested function scope rules apply to lambdas as well, they are also easier to use as callback handlers, as of Python 2.2—they automatically see names in the functions in which they are coded and no longer require passed-in defaults in most cases. This is especially handy for accessing the special self instance argument that is a local variable in enclosing class method functions (more on classes in Part VI): class MyGui: def makewidgets(self): Button(command=(lambda: self.onPress("spam"))) def onPress(self, message): ...use message... In prior releases, even self had to be passed in to a lambda with defaults. * * *
Another very common application of lambda is to define inline callback functions for Python’s tkinter GUI API (this module is named Tkinter in Python 2.6). For example, the following creates a button that prints a message on the console when pressed, assuming tkinter is available on your computer (it is by default on Windows and other OSs):