Higher-order functions and lambdas

INPUT · Slides

Do the same thing to everything

01 / 07

You can already do this with a comprehension

"I want everything in this list doubled." Chapter 9 turned that into a single line.

This chapter adds another way of writing it — a built-in function called map.

What it does is very nearly what a comprehension does. You learn it anyway because it turns up in other people's code. Writing it is optional; reading it is not.

numbers = [1, 2, 3]print([x * 2 for x in numbers])

Result

[2, 4, 6]

02 / 07

Hand a function to map

map takes two things: a function and something you can loop over.

  • map(f, xs) … applies f to each thing in xs

What you pass is the function itself, so double gets no parentheses. Put them there and you would be passing the result of calling it. Exactly the same conversation as key=len in the last group.

And what comes back is not a list. It is a value of its own kind, called map.

def double(x):    return x * 2numbers = [1, 2, 3]m = map(double, numbers)print(type(m))

Result

<class 'map'>

03 / 07

Print it as it is and you see nothing

Here is the biggest trap in map. Printing it as it is does not show you the contents.

numbers = [1, 2, 3]print(map(double, numbers))<map object at 0x1234abcd>

The address on the end changes every time you run it. It is no use for checking an answer, and there is nothing to read in it anyway.

The reason is that map has not done the work yet. Like the hand-them-out-one-at-a-time helper from Chapter 8 — an iterator — it makes one only when asked. What you are holding is a booking slip saying "I will double these for you".

04 / 07

Put it through list and you can see it

To turn the booking slip into real values, put it through list(...). That pulls everything out and hands you a list.

Use map, take it with list. Learn the two as one shape. Whether you are showing it or keeping it around as a list, putting it through cannot go wrong.

def double(x):    return x * 2numbers = [1, 2, 3]print(list(map(double, numbers)))

Result

[2, 4, 6]

05 / 07

Side by side with a comprehension

Put the two next to each other. The results are identical.

list(map(double, numbers))
[double(x) for x in numbers]

Which reads better is partly a matter of taste. That said, Python tends to prefer the comprehension. There is no wrapping in list, and for something as small as doubling you can write x * 2 straight out, with no lambda and no def.

def double(x):    return x * 2numbers = [1, 2, 3]a = list(map(double, numbers))b = [double(x) for x in numbers]print(a)print(b)print(a == b)

Result

[2, 4, 6]
[2, 4, 6]
True

06 / 07

Take it out once and it is empty

Being a booking slip has one more consequence. Take the contents out once and the second time there is nothing there.

Chapter 8 said it: an iterator cannot be wound back once it has handed everything out. map behaves in exactly the same way.

So if you want the result twice, turn it into a list first and put it in a variable. Carry the booking slip around instead and the second attempt gives you an empty list, and you will be left scratching your head.

def double(x):    return x * 2numbers = [1, 2, 3]m = map(double, numbers)print(list(m))print(list(m))

Result

[2, 4, 6]
[]

07 / 07

Which should you write

Writing something new of your own, the comprehension is the one to reach for. You cannot forget the list, and there is no second time coming up empty.

You learn map anyway because you have to be able to read it. People arriving from other languages write map, and it turns up inside libraries.

Be able to read both. That is what this lesson is for. Next comes the other half: not "do this to everything" but "keep only what you want".