Replacing map() With Pythonic Code
In many cases, you can replace a call to the
map() function using either a list comprehension or a generator expression. Let’s compare all three.
We’ve seen how the
map() function works. We have as a first argument the function that we want to map at every element of an iterable. So, in this case, we only have one iterable, which means that the function in the
map() call has only one positional argument.
00:26 We know that this is going to return a map object.
00:30 Now, what you’ll do with this map object depends on what your application asks for. If you don’t want to necessarily generate a list with this map object and maybe all you want to do is iterate over the object, then you’ll probably want to just keep it like this as a map object and pass it on to whatever code that needs to iterate over it. Now, the list comprehension, which you’ve probably seen before, is going to return or generate a list.
The basic idea is that you’re building this list incrementally, and so you can sort of shorten this instead of using the typical way where you would first initialize an empty list and then append to it the values of the function at every element
x of the iterable—you could do all of that, say, with this one line, and this is the list comprehension. And then lastly, the generator expression. It’s going to return a generator object, which is also an iterator, just like the map object is.
01:30 The only difference in the syntax between the list comprehension and the generator expression is that the square brackets in the list comprehension are just parentheses in the generator expression. And so, again, the generator expression is going to return an iterator and it’s going to function pretty much in the same way as the iterator returned by the map object.
01:55 Now, you’re probably already using list comprehensions and maybe even also generator expressions. List comprehensions are very popular among Python developers, and so if you want to write your programs so that they look more like what is familiar to other Python developers, you may want to use a list comprehension or maybe even a generator expression.
Ultimately, what you decide to do—whether you want to use the
map() function or a list comprehension or a generator expression—may depend on what’s your application and what you’re trying to do.
The list comprehension and the generator expressions, they’re a bit more explicit and they read almost like pure English. “We want to generate a list of the values of the function at each element
x of the iterable.”
Now, one situation where the
map() function may actually be a little bit more readable is when the function that you want to map takes on more than one positional argument. So in this example, this function here takes on two positional arguments and those are being fed in by one element from the
iterable_1 and another one from the
iterable_2, one at a time.
We’ve seen this type of code before. Now, to generate an iterator using a generator expression, we would need the following code here. We would first need to zip the
iterable_1 and the
iterable_2. This will return an iterator and the iterator will yield, one at a time, one element from the
iterable_1 and the corresponding element from the
And this will return, on demand, an iterable containing two elements, and then we go ahead and unpack those one at a time using the variables
y, and those are the values or the arguments that we’re feeding into the function.
So, this generator expression is pretty explicit. It’s telling us exactly what we’re sort of needing to do. We need to combine these two iterables and generate a tuple, one at a time, of the
(x, y) values, and again feeding it into the
Now, suppose instead we had a function that took on, say, three positional arguments. So, with three iterables the code with the
map() function would be pretty much the same, right?
function() takes on three positional arguments, we would have then therefore a third iterable. And this time instead for the generator expression, we may want to use the unpacking operator (
So instead of doing the unpacking over here in the
for statement that are returned by the
zip() iterator, we would just unpack it into the
function() and just save a little bit of code that way. Now, personally, in this case, I would probably prefer the
map() call over this sort of longer generator expression, but really it all depends on what you want to do and how you think about what you’re doing in the particular problem that you’re trying to solve.
Let’s do a quick example where we compare the use of the
map() function versus, say, a generator expression. So, say you have some functions.
Say it is a function that takes three numbers and returns the sum of the cubes of the three numbers. This function, we’ll call it
sum_of_cubes(). And again, it takes three numbers, say
z, and it just simply returns the sum of the cubes of
Let’s create three lists that will contain values of
z’s, and we’ll call these lists
05:39 And these I’ll just bring up from my history in the REPL, and you can really put down here any lists that you want and they don’t even have to have the same number of elements, but we’ll keep it simple and have it so that each list contains three elements.
So, let’s go ahead and call the
map() function on this, and let’s save that in a variable
m. This will be
map(). We want to map the
sum_of_cubes() function using the
x_it iterable, the
y_it, and the
We’ll save that in
m and then we’ll use a generator expression. So in this case, we’re going to call the
sum_of_cubes() function on the values
z, and we want to do this for
zip(), and this is
06:37 You probably want to add a little bit of space here just to make this a bit more readable. This will generate a generator object.
Let’s just confirm, we know that the type of
m is going to be a
map object, and the type of
g is going to be in this case a
And both of these, as we know, are going to be iterators, and so we can iterate over them as we would—say if we needed them in a
for loop or if we wanted to generate a list out of them, we can go ahead and call the
list() function. You know, but here what you could do is just sort of compare what you prefer if you had to write some code that had to do something like this.
If we were using the generator expression, it’s a little bit more explicit. We are first zipping up the three iterables, or the three lists, into an iterator that will return, one at a time, an iterable that we unpack with
z, and those are being fed into the
Whereas with the
map() call, we just simply use the function that we want to map over the elements obtained by zipping, sort of in the background, coming from the three iterables that we’re passing in.
So, let’s just go ahead and view those, so let’s
list(g), and those are going to be two lists of the same values.
Now, another way you can write the generator expression—if I bring that up again—is instead of doing the unpacking over here, we can do the unpacking with the unpacking operator and feed that into the
So here we’ll write
*xyz and that’ll generate the same list as before, except that the unpacking is being done inside the call to the
This ends this quick lesson on comparing calls to the
map() function versus, say, generator expressions. Ultimately, you’re going to be the one that decides whether it makes more sense maybe to use a
map() call or a list comprehension, or maybe even a generator expression. But of course, one thing to keep in mind is if you’re writing code that you think others may want to take a look at or may want to contribute to, then list comprehensions and generator expressions appear quite a bit in Python code, and so you may want to choose those instead.
Become a Member to join the conversation.