了解在Python中如何使用 lambda, map, filter 和 reduce 函数来转换数据结构
Photo by Markus Spiske on Unsplash
面向对象的编程通过封装移动部件来让代码变得易于理解,而函数式编程则通过尽量减少移动部件来使代码变得易于理解。— Michael Feathers
世界上有很多种语言,它们可以归类的类别也是如此。编程示例是一种基于编码风格和语言方式去尝试把不同语言分类的途径。编程示例本质上就是一种风格和编程方式。
大多数的时候,我们认为 Python 是面向对象语言, 我们以类(classes),对象(objects),和方法(methods)对数据进行模拟。但是,OOP 也有几种替代方案,函数式编程就是其中之一。
以下是业界流行的一些传统编程示例:
常规编程示例:来源 Wikipedia
1、函数式编程(FP)
函数式方程示例
根据维基百科,函数式方程是一种函数式示例, 是构建计算机程序结构和基本要素的一种风格。它将计算视为数学函数的评估和避免改变数据和其状态。
上面的定义有可能一开始听起来很让人迷惑,但它基本上试图提出以下观点:
FP 依赖于方程,一切都是使用函数来完成的。并且,FP 专注于定义去做什么,而不是执行某些操作。这种函数示例被认为是一级函数式。这意味着函数被视为任何其它对象,我们可以把他们分配给变量或者将他们嵌入其它函数式。函数式使用的数据必须是不可变的。这意味着如果我们需要修改列表中的数据,我们需要新建一个包含更新值的新列表,而不是操纵现有的列表。写入FP的程序应该是无状态的。无状态的方程式不能表达其过去状态。函数式编程每一次执行任务,就像他们第一次执行一样。简而言之,这些函数仅依赖于作为参数传递给他们的数据,而不依赖于外部数据。惰性是 FP 另外一个特性,我们不需要计算我们不需要的东西,工作只在需要时完成。
如果现在有所了解,下面是 OOP 和 FP 很好的对比图表,这将概念变得更明显。
图片来源:
Python提供了 lambda,filter,map 和 reduce 等功能,可以轻松演示函数式编程的概念。可以从关联的 Github 存储库 访问本文中使用的所有代码.
/parulnith/Elements-of-Functional-Programming-in-Python
2、Lambda 表达式
Lambda 表达式 - 也称为“匿名函数” - 允许我们在一行中创建和使用函数。当我们需要一个只能使用一次的短函数时它们很有用。它们主要与 map,filter 和 sort 方法结合使用,我们将在本文后面讲到。
让我们用 Python 编写一个函数来计算5x + 2
. 标准的做法是定义一个函数。
现在让我们使用 Lambda 函数计算相同的表达式。要创建 lambda 表达式,我们输入关键字 lambda,后面输入函数。接下来,我们输入一个冒号,后面是返回值的表达式。
这个 lambda 函数将获取输入 x 并返回5x + 2
,就像之前的函数一样 f 。但是,有一个问题。Lambda 不是函数的名称。它是一个 Python 关键字,表示接下来是一个匿名函数。那么我们如何使用它呢?一种方法是给它起一个名字。
让我们称之为 lambda 表达式g
。现在,我们可以像任何其他功能一样使用它。
具有多个输入值的Lambda表达式
下面的示例显示了lambda函数如何在有或没有输入值的情况下使用。
没有输入值的Lambda表达式
现在,让我们看看 Lambda 函数的常见用法,我们不为它指定名称。假设我们列出了前七位美国总统的名单,我们想用他们的姓氏对这份名单进行排序。我们将创建一个提取姓氏的 Lambda 函数,并将其用作排序值。
map,filter 和 reduce 函数简化了使用列表的工作。与 lambda 表达式一起使用时,它们通过在一行代码中完成大量工作,有助于使我们的生活更轻松。
3、Map 函数
Map 函数对每一个数值进行迭代并产生的结果。与列表一起使用时,Map通过将函数应用于在input_list中的所有值,将给定列表转换为新列表。
句法
map(function_to_apply, iterables)
用法
假设我们有一个函数来计算一个立方体的体积,给定它的边长 a
def volume(a): """volumne of a cube with edge 'a'""" return a**3
如果我们需要计算具有不同边长的不同立方体的体积,该怎么办?
# Edge length in cmedges = [1,2,3,4,5]
有两种方法可以做到这一点, 一种是使用直接方法,另一种是使用 map 函数。
现在让我们看看如何使用 map 函数使用一行代码来完成此任务。
Map 函数有两个参数。第一个是函数,第二个是我们的 list ,tuple 或任何其他可迭代对象。这里,map 函数将 volume 函数应用于列表中的每个元素。
这里要注意的一件重要事情是 map 函数的输出不是列表而是 map 对象,它是结果的迭代器。但是,我们可以通过将映射传递构造列表将其转换为列表。
例子
现在让我们看一个演示 lambda 函数与 map 函数一起使用的例子。我们有一个包含 5 个人姓名和高度的元组列表。每个高度都以厘米为单位,我们需要将其转换为英尺。
我们将首先使用 lambda 表达式编写转换器函数,该表达式将接受元组作为输入,并且还将返回元组
4、Filter 函数
Filter 函数从可迭代元素中构造一个迭代器,并且函数返回符合值。这意味着 filter 函数用于从 list,tuple 或其他数据集合中选择某些数据,因此叫这个名字。
句法
filter(function, iterable)
用法
让我们看一个例子,我们想要从给定的输入列表中获取大于 5 的所有数字的列表。
我们首先创建一个lambda函数来测试输入,看它是否大于5。接下来,我们传入数据列表。Filter 函数仅返回函数为正确的数据。再一次,返回值不是列表,而是 filter 对象。必须将此对象传递给列表构造函数才能获得输出。
例子
一个有趣的例子,当数据由缺失值组成时,filter 函数发生作用。这是一份包含亚洲一些国家的清单。注意很多字符串都是空的。我们将使用 filter 功能来删除这些缺失值。我们将空集作为第一个参数,第二个参数是刚刚提到的数据列表。
这会过滤掉布尔设置中被视为否的所有值。
5、Reduce 函数
Reduce 功能有点不寻常,从 Python 3 开始,它不再是内置函数。相反,它已被移动到 functools 模块。reduce
函数通过将给定列表转换为单个值,通过列表中值从左到右顺序累加并返回一个值。
用法
reduce(func, seq)
reduce 持续将函数 func() 应用于序列 seq 并返回单个值。
用法
让我们通过一个计算整数列表连乘的简单例子来说明 reduce 函数的工作原理。
下图显示了计算的中间步骤:
在 Python 中使用 Reduce 函数
然而,Python 的创建者 Guido van Rossum 不得不对 Reduce 函数这样说:
如果你确实需要,请使用 functools.reduce; 但是,99% 的时间表明 for 循环更具有可读性。
上面的程序也可以使用显式的 for 循环编写:
例子
Reduce 函数可以用单行代码找出整数列表中的最大值。确实在 Python 中存在一个内置函数 max(),它也通常可以用于此目的 max(list_name)。
6、列表推导式: 替代 map, filter 和 reduce
列表推导式(list comprehensions) 是一种在Python 中定义和创建列表的方法。在大多数情况下,列表理解使我们可以在一行代码中创建列表,而无需担心初始化列表或设置循环。
它也是 lambda 函数以及函数 map(),filter()和reduce()的替代品。有些人发现它是一种更加体现 python 的编写函数的方式,并且发现它更容易理解。
句法
用法
让我们尝试用 列表推导式来演示上面部分使用的示例。
列表推导式 vs. Map 函数
我们将 map 函数与 lambda 函数结合使用,将高度列表从 cm 转换为英尺。让我们使用列表推导式来实现相同的结果。
列表推导式 vs. Filter 函数
我们使用过滤功能从亚洲国家/地区列表中删除缺失值。让我们使用列表推导式来获得相同的结果。
列表推导式 vs. Reduce 函数
类似地,我们可以使用列表推导式来快速确定包含整数列表的最大值,而不是使用 lambda 和 reduce。
我们在上面例子中使用了相应函数式表达,类似于列表推导式,但是使用圆括号而不是方括号。
7、结论
Map,Filter 和 Reduce 函数显着简化了使用列表和其他可迭代数据集的过程。有些人对使用它们有所保留,特别是因为列表推导式似乎更友好,但它们的用处不容忽视。
来源: /elements-of-functional-programming-in-python-1b295ea5bbe0