📅  最后修改于: 2020-08-24 07:13:02             🧑  作者: Mango
的map()
,filter()
和reduce()
功能带来一点函数式编程到Python的。所有这三个都是便利功能,可以用列表推导或循环代替,但可以为某些问题提供更优雅,更简捷的方法。
在继续之前,我们将介绍一些您应该熟悉的内容,然后再介绍上述方法:
什么是匿名函数/方法或lambda?
匿名方法是没有名称的方法,即不像我们使用定义方法时那样绑定到标识符def method:
。
注意:尽管大多数人可以互换使用术语“匿名函数”和“ lambda函数”,但它们并不相同。发生此错误的原因是,在大多数编程语言中,lambda 是匿名的,而所有匿名函数都是 lambda。在Python中也是如此。因此,我们将不在本文中进一步讨论这种区别。
lambda函数(或lambda运算符)的语法是什么?
lambda arguments: expression
将lambda视为没有名称的单行方法。它们的工作原理几乎与Python中的任何其他方法相同,例如:
def add(x,y):
return x + y
可以翻译为:
lambda x, y: x + y
Lambda与普通的Python方法不同,因为它们只能具有一个表达式,不能包含任何语句,并且其返回类型是一个function
对象。因此,上面的代码行不完全返回值,x + y
而是返回计算的函数x + y
。
为什么lambda表达式相关的
map()
,filter()
和reduce()
?
所有这三种方法都将function
对象作为第一个参数。该function
对象可以是带有名称的预定义方法(如def add(x,y)
)。
尽管传递给map()
,filter()
和的函数通常reduce()
只是一次使用,所以通常没有必要定义可引用的函数。
为了避免定义为不同的新功能map()
/ filter()
/ reduce()
需求-一个更优雅的解决办法是使用短,一次性的,匿名的功能,你将只使用一次,永无-拉姆达。
该map()
函数遍历给定iterable中的所有项目,并function
在每个项目上执行作为参数传递的we。
语法为:
map(function, iterable(s))
传递function
我们要使用的对象后,我们可以传递任意数量的可迭代对象:
# Without using lambdas
def starts_with_A(s):
return s[0] == "A"
fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
map_object = map(starts_with_A, fruit)
print(list(map_object))
此代码将导致:
[True, False, False, True, False]
如我们所见,我们最终得到一个新列表,其中对list中的starts_with_A()
每个元素都对其功能进行了评估fruit
。此功能的结果被顺序添加到列表中。
一种更精确的方法是使用lambda:
fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
map_object = map(lambda s: s[0] == "A", fruit)
print(list(map_object))
我们得到相同的输出:
[True, False, False, True, False]
注意:您可能已经注意到,我们已经强制map_object
转换为列表以打印每个元素的值。我们这样做是因为调用print()
列表将打印元素的实际值。调用print()
上map_object
会打印值的内存地址来代替。
该map()
函数返回map_object
一个可迭代的类型,我们也可以打印出如下结果:
for value in map_object:
print(value)
如果您希望该map()
函数返回一个列表,则可以在调用该函数时对其进行强制转换:
result_list = list(map(lambda s: s[0] == "A", fruit))
与相似map()
,filter()
接受一个function
对象和一个可迭代对象并创建一个新列表。
顾名思义,filter()
形成一个新列表,其中仅包含满足特定条件的元素,即function
我们传递的return True
。
语法为:
filter(function, iterable(s))
使用前面的示例,我们可以看到新列表仅包含该starts_with_A()
函数返回的元素True
:
# Without using lambdas
def starts_with_A(s):
return s[0] == "A"
fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
filter_object = filter(starts_with_A, fruit)
print(list(filter_object))
运行以下代码将得到较短的列表:
['Apple', 'Apricot']
或者,使用lambda重写:
fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
filter_object = filter(lambda s: s[0] == "A", fruit)
print(list(filter_object))
打印给我们相同的输出:
['Apple', 'Apricot']
reduce()
工作原理与map()
和不同filter()
。它不会根据function
我们传递的和可迭代返回一个新列表。而是返回一个值。
此外,在Python 3中,reduce()
它不再是内置函数,可以在functools
模块中找到。
语法为:
reduce(function, sequence[, initial])
reduce()
通过调用function
序列中前两项传递的we来工作。所返回的结果将在下一个(在本例中为第三个)元素的function
另一个调用中function
使用。
重复此过程,直到我们遍历了序列中的所有元素。
可选参数initial
(如果存在)在此“循环”的开始处使用,并在第一次调用中使用第一个元素function
。在某种程度上,如果提供的话,该initial
元素是第一个元素之前的第0个元素。
reduce()
比map()
和更难理解filter()
。因此,让我们看一个逐步的示例:
[2, 4, 7, 3]
然后将add(x, y)
函数传递到reduce()
该列表的旁边,而没有initial
值reduce()
调用add(2, 4)
并add()
返回6
reduce()
调用add(6, 7)
(上次调用的结果add()
和列表中下一个元素作为参数的结果),并add()
返回13
reduce()
调用add(13, 3)
并add()
返回16
reduce()
返回16
如果我们提供了一个initial
值,唯一的不同是额外的步骤-1.5。在第2步中哪里reduce()
调用add(initial, 2)
和使用该返回值。
让我们继续使用该reduce()
函数:
from functools import reduce
def add(x, y):
return x + y
list = [2, 4, 7, 3]
print(reduce(add, list))
运行此代码将产生:
16
同样,这可以使用lambdas编写:
from functools import reduce
list = [2, 4, 7, 3]
print(reduce(lambda x, y: x + y, list))
print("With an initial value: " + str(reduce(lambda x, y: x + y, list, 10)))
该代码将导致:
16
With an initial value: 26
如前所述,这些功能是便利功能。它们在那里,因此您可以避免编写更多繁琐的代码,但避免同时使用它们和lambda表达式。
不要强迫使用这些工具,因为“您可以”,因为它通常会导致难以维护的难以理解的代码。仅当您完全清楚函数或lambda表达式后,才使用它们。
如果您发现自己在努力将必要的逻辑装入一个map()
函数或一个lambda表达式中,则最好编写稍长的for-loop / defined方法,并避免以后不必要的混乱。