Dark theme

Key ideas in depth: lambdas and sorting


Lambdas

One purpose of lambdas and list comprehensions is to remove the potential for side effects with variables. A side effect is any unexpect use of a variable. In general, variables are highly exposed to side effects as anything in their scope can alter or access them. This is true to the extent that some functional programmers talk about any use of a variable as being a side effect. As we saw when we looked at , the potential for picking up the wrong variable isn't an abstract issue. To minimise potential errors we'd like to limit the use of variables to only the lines we need them. Lambdas and list comprehensions are two way of doing this: as the scope of the variables is very limited. The Python documentation gives the following example:

Here's some standard code creating a list of squares of numbers:

squares = []
for x in range(10):
    squares.append(x**2)
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

The problem is that it uses the squares variable which may or may not exist before, and will exist after this runs. To prevent this, we could use either of the following, which don't create that variable:

squares = list(map(lambda x: x**2, range(10)))
squares = [x**2 for x in range(10)]

Neither of these create any variables outside the scope of their statements. It is worth noticing that lambdas are generally avoided by Python programmers, as (as can be seen above) list comprehensions were designed to replace them with more elegance. Nevertheless, they have their uses.


Sorting

Sorting may seem of limited use, as you can either sort as-is, or pass in a function that takes in a single value (of which there are a limited number). However, you can actually build some reasonably sophisticated sort routines. Let's walk through an example. Say we have:

s = ["a:bee","b:apple","c:zoo","d:coffee"]

and we want to sort the main words alphabetically. There's no function that will take in a word and return it minus the two left character. However, there is:

str.rpartition(sep)
which returns a tuple split at sep. The question is, how do we use this method, which takes a separator as whatever self it is called on, then get the second part of the tuple?

The operator library includes functions for invoking operations on variables:

itemgetter() # get an item
attrgetter() # get an internal variable
methodcaller() # invoke a method

So, we can sort using rpartition, and then sort again on the second item in the returned tuple. Here's the code:

import operator

s = ["a:bee","b:apple","c:zoo","d:coffee"]

s2 = sorted(
    sorted(
        s,key=operator.methodcaller("rpartition",":")
    )
    , key=operator.itemgetter(2)
    )
print(s2)

Although this looks complicated, and indeed is, the message is firstly that with a little persistence most things can be achieved, and secondly it pays to read around the standard library and get used to it so you know roughly where to look when something stops you moving forward.