如何在Python 3中使用filter、map和reduce

2024-04-24 20:10:10 发布

您现在位置:Python中文网/ 问答频道 /正文

filtermapreduce在Python 2中工作得很好。下面是一个例子:

>>> def f(x):
        return x % 2 != 0 and x % 3 != 0
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]

>>> def cube(x):
        return x*x*x
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

>>> def add(x,y):
        return x+y
>>> reduce(add, range(1, 11))
55

但在Python 3中,我接收到以下输出:

>>> filter(f, range(2, 25))
<filter object at 0x0000000002C14908>

>>> map(cube, range(1, 11))
<map object at 0x0000000002C82B70>

>>> reduce(add, range(1, 11))
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    reduce(add, range(1, 11))
NameError: name 'reduce' is not defined

如果有人能解释一下原因,我将不胜感激。

为了进一步清晰起见,代码截图:

IDLE sessions of Python 2 and 3 side-by-side


Tags: andaddmapreducemostreturnobjectdef
3条回答

作为其他答案的补充,这听起来像是上下文管理器的一个很好的用例,它将这些函数的名称重新映射到返回列表并在全局命名空间中引入reduce的函数。

快速实现可能如下所示:

from contextlib import contextmanager    

@contextmanager
def 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 noiters(map):
    from operator import add
    print(reduce(add, range(1, 20)))
    print(map(int, ['1', '2']))

打印内容:

190
[1, 2]

就我的2美分:-)

您可以阅读What's New In Python 3.0中的更改。当你从2.x移到3.x时,你应该仔细阅读它,因为很多东西已经改变了。

这里的全部答案都是从文档中引用的。

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.
  • [...]

有意将mapfilter的功能更改为返回迭代器,并将reduce从内置中移除并放置在functools.reduce中。

因此,对于filtermap,您可以用list()来包装它们,以便像以前一样查看结果。

>>> 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
>>>

现在的建议是用生成器表达式或列表理解替换map和filter的用法。示例:

>>> 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]
>>>

他们说for循环99%的时间比reduce更容易阅读,但我还是坚持使用functools.reduce

编辑:99%的数据直接从Guido van Rossum编写的What’s New In Python 3.0页面中提取。

相关问题 更多 >