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()
andfilter()
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 ismap()
invoked for the side effects of the function; the correct transformation is to use a regularfor
loop (since creating a list would just be wasteful).- [...]
- [...]
- Removed
reduce()
. Usefunctools.reduce()
if you really need it; however, 99 percent of the time an explicitfor
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 :-)