353

filter, map, 并reduce在 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

如果有人能向我解释为什么会这样,我将不胜感激。

代码截图更清楚:

Python 2 和 3 的 IDLE 会话并排

4

8 回答 8

376

您可以阅读Python 3.0 中的新增功能中的更改。当您从 2.x 迁移到 3.x 时,您应该仔细阅读它,因为已经发生了很多变化。

这里的整个答案是文档中的引用。

视图和迭代器代替列表

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

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

内置

  • [...]
  • 已删除reduce()functools.reduce()如果您确实需要,请使用它;但是,在 99% 的情况下,显式for循环更具可读性。
  • [...]
于 2012-11-30T04:22:03.457 回答
98

mapand的功能filter被有意更改为返回迭代器,reduce 被从内置中删除并放置在functools.reduce.

因此,对于filter和,您可以像以前一样map将它们包装起来以查看结果。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 中的新增功能页面。

于 2012-11-30T04:17:44.600 回答
12

作为其他答案的补充,这听起来像是上下文管理器的一个很好的用例,它将这些函数的名称重新映射到返回列表并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 美分 :-)

于 2016-08-31T04:00:39.980 回答
9

由于该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)
于 2018-06-25T02:20:24.877 回答
4

map、filter 和 reduce 的优点之一是当您将它们“链接”在一起以执行复杂的操作时它们变得多么清晰。但是,内置语法不清晰,都是“倒退”的。所以,我建议使用这个PyFunctional包(https://pypi.org/project/PyFunctional/)。 这是两者的比较:

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

PyFunctional 版本

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

“我有一系列航班目的地。如果 city 在 dict 值中,我想从中获取 dict 键。最后,过滤掉我在此过程中创建的空列表。”

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

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())
               )
    )
于 2020-05-23T05:53:35.937 回答
2

以下是 Filter、map 和 reduce 函数的示例。

数字 = [10,11,12,22,34,43,54,34,67,87,88,98,99,87,44,66]

//筛选

奇数 = 列表(过滤器(λ x:x%2 != 0,数字))

打印(奇数)

//地图

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

打印(乘以 2)

//减少

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

从 functools 导入减少

sumOfNumbers = reduce(lambda x,y: x+y, 数字)

打印(总和)

于 2018-12-18T07:35:26.953 回答
0
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

于 2020-09-22T16:28:49.500 回答
-1

拉姆达

尝试了解普通的 def 定义函数和 lambda 函数之间的区别。这是一个返回给定值的立方体的程序:

# Python code to illustrate cube of a number 
# showing difference between def() and lambda(). 
def cube(y): 
    return y*y*y 
  
lambda_cube = lambda y: y*y*y 
  
# using the normally 
# defined function 
print(cube(5)) 
  
# using the lamda function 
print(lambda_cube(5)) 

输出:

125
125

不使用 Lambda:

  • 在这里,它们都返回给定数字的立方体。但是,在使用 def 时,我们需要定义一个名为 cube 的函数,并且需要向它传递一个值。执行后,我们还需要使用 return 关键字从调用函数的位置返回结果。

使用 Lambda:

  • Lambda 定义不包含“return”语句,它总是包含一个返回的表达式。我们还可以将 lambda 定义放在任何需要函数的地方,我们根本不必将它分配给变量。这就是 lambda 函数的简单性。

Lambda 函数可以与内置函数一起使用,例如filter(),map()reduce().

lambda() 和 filter()

Python 中的filter()函数接受一个函数和一个列表作为参数。这提供了一种优雅的方式来过滤掉序列“sequence”的所有元素,函数为其返回True.

my_list = [1, 5, 4, 6, 8, 11, 3, 12]

new_list = list(filter(lambda x: (x%2 == 0) , my_list))

print(new_list)


ages = [13, 90, 17, 59, 21, 60, 5]

adults = list(filter(lambda age: age>18, ages)) 
  
print(adults) # above 18 yrs 

输出:

[4, 6, 8, 12]
[90, 59, 21, 60]

lambda() 与 map()

Python 中的map()函数接受一个函数和一个列表作为参数。使用 lambda 函数和一个列表调用该函数,并返回一个新列表,其中包含该函数为每个项目返回的所有 lambda 修改项。

my_list = [1, 5, 4, 6, 8, 11, 3, 12]

new_list = list(map(lambda x: x * 2 , my_list))

print(new_list)


cities = ['novi sad', 'ljubljana', 'london', 'new york', 'paris'] 
  
# change all city names 
# to upper case and return the same 
uppered_cities = list(map(lambda city: str.upper(city), cities)) 
  
print(uppered_cities)

输出:

[2, 10, 8, 12, 16, 22, 6, 24]
['NOVI SAD', 'LJUBLJANA', 'LONDON', 'NEW YORK', 'PARIS']

减少

reduce()map()与和的工作方式不同filter()。它不会根据function我们传递的和迭代返回一个新列表。相反,它返回一个值。

此外,在 Python 3reduce()中不再是内置函数,它可以在functools模块中找到。

语法是:

reduce(function, sequence[, initial])

reduce()通过调用function我们为序列中的前两项传递的来工作。返回的结果与下一个(在本例中为第三个)元素一起function用于另一个调用中。function

如果存在可选参数initial,则在此“循环”的开头使用第一次调用中的第一个元素function。在某种程度上,该initial元素是第一个元素之前的第 0 个元素(如果提供)。

lambda() 和 reduce()

Python 中的 reduce() 函数接受一个函数和一个列表作为参数。该函数使用 lambda 函数和一个可迭代的函数调用,并返回一个新的缩减结果。这对可迭代的对执行重复操作。

from functools import reduce

my_list = [1, 1, 2, 3, 5, 8, 13, 21, 34] 

sum = reduce((lambda x, y: x + y), my_list) 

print(sum) # sum of a list
print("With an initial value: " + str(reduce(lambda x, y: x + y, my_list, 100)))
88
With an initial value: 188

这些函数是便利函数。它们在那里,因此您可以避免编写更繁琐的代码,但避免过多地使用它们和 lambda 表达式,因为“你可以”,因为它通常会导致难以维护的难以辨认的代码。仅当您在查看函数或 lambda 表达式时绝对清楚发生了什么时才使用它们。

于 2021-01-13T23:05:23.423 回答