How to use filter, map, and reduce in Python 3 How to use filter, map, and reduce in Python 3 python-3.x python-3.x

How to use filter, map, and reduce in Python 3


You can read about the changes in What's New In Python 3.0. You should read it thoroughly when you move from 2.x to 3.x since a lot has been changed.

The whole answer here are quotes from the documentation.

Views And Iterators Instead Of Lists

Some well-known APIs no longer return lists:

  • [...]
  • map() and filter() return iterators. If you really need a list, a quick fix is e.g. list(map(...)), but a better fix is often to use a list comprehension (especially when the original code uses lambda), or rewriting the code so it doesn’t need a list at all. Particularly tricky is map() invoked for the side effects of the function; the correct transformation is to use a regular for loop (since creating a list would just be wasteful).
  • [...]

Builtins

  • [...]
  • Removed reduce(). Use functools.reduce() if you really need it; however, 99 percent of the time an explicit for loop is more readable.
  • [...]


The functionality of map and filter was intentionally changed to return iterators, and reduce was removed from being a built-in and placed in functools.reduce.

So, for filter and map, you can wrap them with list() to see the results like you did before.

>>> def f(x): return x % 2 != 0 and x % 3 != 0...>>> list(filter(f, range(2, 25)))[5, 7, 11, 13, 17, 19, 23]>>> def cube(x): return x*x*x...>>> list(map(cube, range(1, 11)))[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]>>> import functools>>> def add(x,y): return x+y...>>> functools.reduce(add, range(1, 11))55>>>

The recommendation now is that you replace your usage of map and filter with generators expressions or list comprehensions. Example:

>>> def f(x): return x % 2 != 0 and x % 3 != 0...>>> [i for i in range(2, 25) if f(i)][5, 7, 11, 13, 17, 19, 23]>>> def cube(x): return x*x*x...>>> [cube(i) for i in range(1, 11)][1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]>>>

They say that for loops are 99 percent of the time easier to read than reduce, but I'd just stick with functools.reduce.

Edit: The 99 percent figure is pulled directly from the What’s New In Python 3.0 page authored by Guido van Rossum.


As an addendum to the other answers, this sounds like a fine use-case for a context manager that will re-map the names of these functions to ones which return a list and introduce reduce in the global namespace.

A quick implementation might look like this:

from contextlib import contextmanager    @contextmanagerdef noiters(*funcs):    if not funcs:         funcs = [map, filter, zip] # etc    from functools import reduce    globals()[reduce.__name__] = reduce    for func in funcs:        globals()[func.__name__] = lambda *ar, func = func, **kwar: list(func(*ar, **kwar))    try:        yield    finally:        del globals()[reduce.__name__]        for func in funcs: globals()[func.__name__] = func

With a usage that looks like this:

with noiters(map):    from operator import add    print(reduce(add, range(1, 20)))    print(map(int, ['1', '2']))

Which prints:

190[1, 2]

Just my 2 cents :-)