A few weeks ago, I introduced you to functional programming in Python. Today, I'd like to go further into this topic and show you so more interesting features.
What do we call lambda functions? They are in essence anonymous functions. In order to create them, you must use the
>>> lambda x: x <function <lambda> at 0x102e23620>
In Python, lambda functions are quite limited. They can take any number of arguments; however they can contain only one statement and be written on a single line.
They are mostly useful to be passed to high-order functions, such as
>>> list(map(lambda x: x * 2, range(10))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
This will apply the anonymous function
lambda x: x * 2 to every item returned by
Since lambda functions are limited to being one line long, it's often that they are used to specialize longer version of an existing function:
def between(number, min=0, max=1000): return max > number > min # Only returns number between 10 and 1000 filter(lambda x: between(x, min=10), range(10000))
Our lambda is finally just a wrapper of the
between function with one of the argument already set. What if we would have a better way, without the various lambda limitations, to write that? That's where
functools.partial comes handy.
import functools def between(number, min=0, max=1000): return max > number > min # Only returns number between 10 and 1000 atleast_10_and_upto = functools.partial(between, min=10) # Return number betweens 10 and 1000 filter(atleast_10_and_upto, range(10000)) # Return number betweens 10 and 20 filter(lambda x: atleast_10_and_upto(x, max=20), range(10000))
functools.partial function returns a specialized version of the
between function, where
min is already set. We can store them in a variable, use it, reuse it, as much as we want. We can pass it a
max argument, as shown in the second part — using a
lambda! You can mix and matches those two as you prefer and what seems clearer for you.
There is a type of lambda function that is pretty common: the attribute or item getter. They are typically used a
key function for sorting or filtering.
Here's a list of 200 tuples containing two integers
(i1, i2). If you want to use only
i2 as the sorting key, you would write:
mylist = list(zip(range(40, 240), range(-100, 100))) sorted(mylist, key=lambda i: i)
Which works fine, but make you use
lambda. You could rather use the
import operator mylist = list(zip(range(40, 240), range(-100, 100))) sorted(mylist, key=operator.itemgetter(1))
This does the same thing, except it avoids using
lambda altogether. Cherry-on-the-cake: it is actually 10% faster on my laptop.
I hope that'll make you write more functional code!