[Tutor] list comprehension equivalent to map(function, list item)

Steven D'Aprano steve at pearwood.info
Sat Dec 14 04:54:42 CET 2013


On Fri, Dec 13, 2013 at 08:03:57PM -0500, Bo Morris wrote:

> i have the following simple function that iterates over the list. 

Actually, no it doesn't. One important skill of being a programmer is 
precision of language. The function "add" you show below does not 
iterate over the list, it is the *map* function which does the 
iteration.


> It passes the list item into the function and adds the numbers. 

Again, not so much. When you talk about adding up the numbers, given 
numbers like 5, 3, 2 I would expect to get 10 as the answer. That is not 
what your function does: it adds one to *each* number, alone.

Now that I've lectured you pedantically on precision of language, which 
I hope you'll take in the constructive spirit it is intended, let me 
answer your actual question:


> What would be the
> equivalent way of writing the "map" portion with list comprehension? My
> code is as follows:
> 
> def add(number):
>     print 1 + int(number)
> 
> x = ['2', '4', '6', '8', '10', '12']
> map(add, x)


Converting a map to a list comprehension is simple:

    map(function, items)

becomes:

    [function(item) for item in items]


So your example simply becomes [add(s) for s in list_of_strings]


A couple of other points:

(1) The more work a variable is used for, the more descriptive its name 
should be. Variables which are used once can be a single letter. 
Temporary variables which don't last very long also can be a single 
letter. It is conventional to use a few single letter names:

i, j, k: loop variables
n, m: integers
x, y: floats or decimals
s: strings

but only when they represent generic values. If possible, you should 
give variables names which explain *what they are* (such as 
"list_of_strings") or even better, *what they are used for* (such as 
"scores", "width", "number_of_pages", etc.)


(2) In your example, your "add" function actually does two things:

    - it *calculates* a result (adding one to a number);
    - it *displays* that result (print).

In general, it is best to keep those two parts separate. Why? Because 
good, effective programming involves putting parts together to make 
bigger parts. Once you introduce a print into a function, you can't 
really combine that part into a new more powerful part. You are now 
committed to *only* printing the calculation result, even if what you 
actually want to do is to perform more calculations on it.

An example: suppose that, after adding one, you then want to double the 
result. You might think that you could do this:

def double(number):
    print 2*number

double(add(20))


That's exactly the sort of putting building blocks together that 
programming is all about. But if you try it, you'll see that it doesn't 
work. You'll get a mysterious error something like this:

TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'

Why? Because your "add" function takes the calculated result and prints 
it, then throws the result away. Since the function doesn't return a 
value for later use, Python automatically returns the special None 
value, which you can think of as meaning something like "nothing at 
all". What happens when you try to double None? You get an error.

The way to fix this and write functions which can be used as building 
blocks is to use "return" instead of "print", then call print at the 
end, only when you want to actually see something:


def add(number):
    return 1 + int(number)

x = ['2', '4', '6', '8', '10', '12']
print map(add, x)

def double(number):
    return 2*number

print double(add(20))


If you have any questions, please don't hesitate to ask!


-- 
Steven


More information about the Tutor mailing list