如何在 Python3中使用 filter、 map 和 reduce

filtermapreduce在 Python2中可以很好地工作:

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

331794 次浏览

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撰写的Python 3.0有什么新特性页面中提取。

你可以阅读有关Python 3.0有什么新特性的变化。当你从2开始的时候,你应该仔细阅读它。X到3。因为已经改变了很多。

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

视图和迭代器而不是列表

一些著名的api不再返回列表:

  • […]
  • map()filter()返回迭代器。如果你真的需要一个列表,一个快速的解决方法是例如list(map(...)),但更好的解决方法通常是使用一个列表综合(特别是当原始代码使用lambda时),或者重写代码,使它根本不需要列表。特别棘手的是map()调用函数的副作用;正确的转换是使用常规的for循环(因为创建列表只是浪费)。
  • […]

Builtins

  • […]
  • reduce()删除。如果你真的需要,可以使用functools.reduce();然而,99%的情况下显式for循环可读性更好。
  • […]

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

这只是我的个人意见:-)

由于reduce方法已从Python3的内置函数中删除,所以不要忘记在代码中导入functools。请查看下面的代码片段。

import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)

下面是Filter, map和reduce函数的例子。

数量=(10、11、12,22岁,34岁,43岁,54岁,34岁,67年,87年,88年,98年,99年,87年,44岁,66年)

/ /过滤

oddNumbers = list(lambda x: x%2 != 0, numbers))

打印(oddNumbers)

/ /地图

multiplyOf2 = list(map(lambda x: x*2, numbers))

打印(multiplyOf2)

/ /减少

由于reduce函数不常用,因此已从Python 3的内置函数中删除。它仍然在functools模块中可用,所以你可以这样做:

从functools导入reduce

sumOfNumbers = reduce(lambda x,y: x+y, numbers)

打印(sumOfNumbers)

map, filter和reduce的优点之一是当你把它们“链接”在一起做一些复杂的事情时,它们变得多么容易读懂。但是,内置语法不清晰,而且都是“向后”的。因此,我建议使用PyFunctional包(https://pypi.org/project/PyFunctional/)。 下面是两者的比较:

flight_destinations_dict = {'NY': {'London', 'Rome'}, 'Berlin': {'NY'}}

PyFunctional版本

非常清晰的语法。你可以说:

"我有一系列的航班目的地。我想从中脱身 如果city在dict值中,则为dict键。最后,过滤掉 我在这个过程中创建的空列表。" < / p >

from functional import seq  # PyFunctional package to allow easier syntax


def find_return_flights_PYFUNCTIONAL_SYNTAX(city, flight_destinations_dict):
return seq(flight_destinations_dict.items()) \
.map(lambda x: x[0] if city in x[1] else []) \
.filter(lambda x: x != []) \

Python默认版本

这一切都是颠倒的。你需要说:

"好的,这是一个列表。我想过滤掉空列表。为什么? 因为如果城市在dict值中,我首先得到dict键。 哦,我要做这个的列表是flight_destinations_dict。" < / p >

def find_return_flights_DEFAULT_SYNTAX(city, flight_destinations_dict):
return list(
filter(lambda x: x != [],
map(lambda x: x[0] if city in x[1] else [], flight_destinations_dict.items())
)
)
from functools import reduce


def f(x):
return x % 2 != 0 and x % 3 != 0


print(*filter(f, range(2, 25)))
#[5, 7, 11, 13, 17, 19, 23]


def cube(x):
return x**3
print(*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

它是这样工作的。要获得map的输出,请使用*或list