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.
Lambda Functions
What do we call lambda functions? They are in essence anonymous functions. In order to create them, you must use the lambda
statement:
>>> 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 map()
:
>>> 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 range(10)
.
functools.partial
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))
The 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.
Common lambda
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[1])
Which works fine, but make you use lambda
. You could rather use the operator
module:
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!
from Planet Python
via read more
No comments:
Post a Comment