10分钟学会python函数式编程

Souleigh ✨ 等级 680 0 0

在这篇文章里,你将学会什么是函数范式以及如何使用Python进行函数式编程。你也将了解列表推导和其它形式的推导。

函数范式

在命令式范式中,通过为计算机提供一系列指令然后执行它们来完成任务。在执行这些指令时,可以改变某些状态。例如,假设你最初将A设置为5,然后更改A的值。这时在变量内部值的意义上,你改变了A的状态。

在函数式范式中,你不用告诉计算机做什么而是告诉他这个东西是什么。比如数字的最大公约数是什么,从1到n的乘积是什么等等。

因此,变量不能变化。一旦你设置了一个变量,它就永远保持这种状态(注意,在纯函数式语言中,它们不是变量)。因此,函数式编程没有副作用。副作用指的是函数改变它自己以外的东西。让我们看一些典型Python代码的示例:

10分钟学会python函数式编程

这段代码的输出是5。在函数式范式中,改变变量是一个很大的禁忌,并且具有影响其范围之外事物的功能也是一个很大的禁忌。函数唯一能做的就是计算一些东西并将其作为结果返回。

现在你可能会想:“没有变量,没有副作用?为什么这样好?“这个问题问得好,我相信大多数人对此感到疑惑。

如果使用相同的参数调用函数两次,则保证返回相同的结果。如果你已经学习了数学函数,你就会知道这个好处。这称为参照透明度。由于函数没有副作用,如果你正在构建一个计算某些事情的程序,你可以加速程序。如果每次调用func(2)都返回3,我们可以将它存储在表中,这可以防止程序重复运行相同的功能。

通常,在函数式编程中,我们不使用循环。我们使用递归。递归是一个数学概念,通常意味着“自我调用”。使用递归函数,该函数将其自身作为子函数重复调用。这是Python中递归函数的一个很好的例子:

10分钟学会python函数式编程

有些编程语言也具有惰性。这意味着他们直到最后一秒才计算或做任何事情。如果你编写一些代码来执行2 + 2,函数程序只会在你真正需要使用结果时计算出来。我们很快就会在Python中探索惰性。

Map

为了理解,我们先来看看迭代是什么。通常可以迭代的对象是列表或数组,但Python有许多不同的类型可以迭代。你甚至可以创建自己的对象,这些对象可以通过实现魔术方法进行迭代。魔术方法就像是一个API,可以帮助你的对象变得更加Pythonic。您需要实现2个魔术方法才能使对象成为可迭代的:

10分钟学会python函数式编程

第一个魔术方法“__iter__”(注:这里是双下划线)返回迭代对象,这通常在循环开始时使用。”__next__“返回下一个对象。

让我们快速进入一个终端调用上面的代码:

10分钟学会python函数式编程

运行将会打印出

10分钟学会python函数式编程

在Python中,迭代器是一个只有__iter__魔术方法的对象。这意味着您可以访问对象中的位置,但不能遍历该对象。一些对象将具有魔术方法__next__而不是__iter__魔术方法,例如集合(在本文后面讨论)。对于本文,我们假设我们接触的所有内容都是可迭代的对象。

现在我们知道什么是可迭代对象了,让我们回到map函数。 map函数允许我们将函数应用于iterable中的每一项。 Map需要2个输入,它们分别是要应用的函数和可迭代对象。

10分钟学会python函数式编程

假设我们有一个数字列表,如下所示:

10分钟学会python函数式编程

我们想要对每个数字进行平方,我们可以编写如下代码:

10分钟学会python函数式编程

Python中函数式的函数是具有惰性的。如果我们不使用“list”,该函数将存储iterable的定义,而不是列表本身。我们需要明确告诉Python“把它变成一个列表”供我们使用。

在Python中突然从非惰性求值转向惰性求值有点奇怪。如果你在函数式思维方式中考虑得更多,而不是命令式思维方式,那么你最终会习惯它。

现在写一个像“square(num)”这样的普通函数虽然很好,但却是不对的。我们必须定义一个完整的函数才能在map中使用它?好吧,我们可以使用lambda(匿名)函数在map中定义一个函数。

Lambda表达式

lambda表达式是一个只有一行的函数。举个例子,这个lambda表达式对给定的数字进行平方:

10分钟学会python函数式编程

让我们运行它:

10分钟学会python函数式编程

这看起来不像一个函数吗?

嗯,这有点令人困惑,但可以解释。我们将一些东西分配给变量“square”。那这个呢:

10分钟学会python函数式编程

告诉Python这是一个lambda函数,输入叫做x。冒号之后的任何内容都是您对输入所做的操作,它会自动返回结果。

简化我们的square程序到只有一行代码,我们可以这样做:

10分钟学会python函数式编程

所以在lambda表达式中,所有参数都在左边,你要用它们做的东西在右边。它有点乱。但事实是,编写只有其他函数式程序员才能阅读的代码会有一定的乐趣。此外,使用一个函数并将其转换为一行代码是非常酷的。

Reduce

Reduce是一个将迭代变成一个东西的函数。通常,你可以在列表上使用reduce函数执行计算以将其减少到一个数字。 Reduce看起来像这样:

10分钟学会python函数式编程

我们经常会使用lambda表达式作为函数。

列表的乘积是每个单独的数字相乘。要做到这一点你将编写如下代码:

10分钟学会python函数式编程

但是使用reduce你可以这样写:

10分钟学会python函数式编程

获得相同的功能,代码更短,并且在使用函数式编程的情况下更整洁。(注:reduce函数在Python3中已不是内置函数,需要从functools模块中导入)

Filter

filter函数采用可迭代的方式,并过滤掉你在该可迭代中不需要的所有内容。

通常,filter需要一个函数和一个列表。它将函数应用于列表中的每一项,如果该函数返回True,则不执行任何操作。如果返回False,则从列表中删除该项。

语法如下:

10分钟学会python函数式编程

让我们看一个小例子,没有filter我们会写:

10分钟学会python函数式编程

使用filter,可以这样写:

10分钟学会python函数式编程

Python作为一门不断发展与普及的语言,还在不断更新中。在学习时,建议找一些学习伙伴一起来学习和讨论,效果更佳。如果想学习Python,欢迎加入Python学习交流群(627012464),一起督促,一起学习。里面有开发工具,很多干货和技术资料分享!

高阶函数

高阶函数可以将函数作为参数并返回函数。一个非常简单的例子如下:

10分钟学会python函数式编程

第二个返回函数的例子:

10分钟学会python函数式编程

开头我说过纯函数式编程语言没有变量。更高阶的函数使这变得更容易。

Python中的所有函数都是一等公民。一等公民被定义为具有以下一个或多个特征:

在运行时创建

在数据结构中分配变量或元素

作为函数的参数传递

作为函数的结果返回

Python中的所有函数都可以用作高阶函数。

Partial application

Partial application(也称为闭包)有点奇怪,但非常酷。您可以在不提供所需的所有参数的情况下调用函数。让我们在一个例子中看到这一点。我们想要创建一个函数,它接受2个参数,一个基数和一个指数,并返回指数幂的基数,如下所示:

10分钟学会python函数式编程

现在我们想要一个专用的平方函数,使用幂函数计算出数字的平方:

10分钟学会python函数式编程

这有效,但如果我们想要一个立方体功能呢?或者求四次方的功能呢?我们可以继续写下它们吗?好吧,你可以。但程序员很懒的。如果你一遍又一遍地重复同样的事情,这表明有一种更快的方法来加快速度,这将使你不再重复。我们可以在这里使用闭包。让我们看一个使用闭包的square函数的示例:

10分钟学会python函数式编程

是不是很酷!我们可以只使用1个参数来调用需要2个参数的函数。

我们还可以使用一个循环来生成一个幂函数,该函数实现从立方体一直到1000的幂。

10分钟学会python函数式编程

函数式编程不是pythonic

您可能已经注意到了,我们想要在函数式编程中做的很多事情都围绕着列表。除了reduce函数和闭包之外,您看到的所有函数都会生成列表。 Guido(Python之父)不喜欢Python中的函数式,因为Python已经有了自己生成列表的方法。

如果你在Python的交互环境下写入”import this“,你将会得到:

10分钟学会python函数式编程

这是Python之禅。这是一首关于Pythonic意味着什么的诗。我们想要涉及的部分是:

There should be one — and preferably only one — obvious way to do it.(应该尽量找到一种,最好是唯一一种明显的解决方案)

在Python中,map和filter可以执行与列表推导(下面讨论)相同的操作。这打破了Python之禅的一个规则,因此函数式编程的这些部分不被视为“pythonic”。

另一个话题是Lambda。在Python中,lambda函数是一个普通函数。 Lambda是语法糖。这两种说法是等价的。

10分钟学会python函数式编程

普通函数可以执行lambda函数可以执行的所有操作,但它不能以相反的方式工作。 lambda函数不能完成普通函数可以执行的所有操作。

这是一个简短的论证,为什么函数式编程不能很好地适应整个Python生态系统。你可能已经注意到我之前提到了列表推导,我们现在将讨论它们。

列表推导

前面,我提到过你可以用map或filter做的任何事情,你可以用列表推导。列表推导是一种在Python中生成列表的方法。语法是:

10分钟学会python函数式编程

让我们对列表中的每个数字进行平方,例如:

10分钟学会python函数式编程

我们可以看到如何将函数应用于列表中的每一项。我们如何应用filter呢?看看前面的代码:

10分钟学会python函数式编程

我们可以将其转换成一个列表推导,像这样:

10分钟学会python函数式编程

列表支持if这样的语句。您不再需要将一百万个函数应用于某些东西以获得您想要的东西。事实上,如果你想尝试生成某种列表,那么使用列表推导看起来会更清晰,更容易。如果我们想要将列表中每个0以下的数字平方怎么办?有了lambda,map和filter你会写:

10分钟学会python函数式编程

这似乎很长很复杂。通过列表推导,它只是:

10分钟学会python函数式编程

列表推导仅适用于列表。map,filter适合任何可迭代的对象,那么这有什么用呢?你可以对你遇到的任何可迭代对象使用任何推导。

其他推导

你可以为任何可迭代对象创建一个推导。

可以使用推导生成任何可迭代的对象。从Python 2.7开始,您甚至可以生成字典(hashmap)。

如果它是可迭代的,则可以生成它。让我们看一下最后一组的例子。

10分钟学会python函数式编程

set是一个元素列表,在该列表中没有元素重复两次。

set中的元素没有顺序。

10分钟学会python函数式编程

您可能会注意到set(集合)与dict(字典)具有相同的花括号。 Python非常聪明。根据你是否为dict提供值,它会知道你是在写dict推导还是set推导。

总结

函数式编程美观而纯粹。函数式代码可以很干净,但也可能很乱。一些Python程序员不喜欢Python中的函数式编程。但我认为,你应该在解决问题时,使用最佳工具。

收藏
评论区

相关推荐

5 行 Python 代码调用电脑摄像头
**前提:** 确保 python 中安装了 opencv-python 模块。如果没有安装,可以参考:[https://pypi.org/project/opencv-python/](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fpypi.org%2Fproject%2Fopencv
Python正则表达式中文手册
Python正则表达式操作指南 =============== 原文出处:[http://www.amk.ca/python/howto/regex/](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fwww.amk.ca%2Fpython%2Fhowto%2Fregex%2F) 原文作者
CentOS升级Python到2.7版本
查看python的版本 python -V Python 2.4.3 1.先安装GCC yum -y install gcc 2.下载Python-2.7.2 wget http://python.org/ftp/python/2.7.2/Python-2.7.2.tar.bz2 3.解压Python-2.7.2
FreeBSD python安装MySQL
fetch https://pypi.python.org/packages/source/M/MySQL-python/MySQL-python-1.2.4.zip unzip MySQL-python-1.2.4.zip cd MySQL-python-1.2.4 python setup.py install ln -s /usr/loca
Jenkins Python Plugin获取环境变量
Jenkins Python Plugin 官方wiki:[https://wiki.jenkins-ci.org/display/JENKINS/Python+Plugin](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwiki.jenkins-ci.org%2Fdisplay%2F
Mac 升级Python 2.7 到 Python 3.7
MAC上默认内置安装了Python 2.7,但是Python 2.7到2020年就会停止维护了,并且有时候会出现依赖库的不兼容问题,那么怎么安装Python 3.X,并且将Python 3.X的版本设置为默认版本呢? ### 安装Python 3.7 有两种安装方式。 第一种是直接下载python3安装包安装: 1、下载地址如下:[https://w
Python 3 教程
Python 3 教程 =========== ![python3](https://www.runoob.com/wp-content/uploads/2014/05/python3.png) Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,
Python List数据的遍历
方式一: <!-- lang: python --> app_list = [1234, 5677, 8899] <!-- lang: python --> for app_id in app_list: <!-- lang: python --> print app_id 输出: 123
Python 全栈开发
**如果你已经玩转了 Python 编程语言语法,肯定想用这些知识,开发一款应用程序,它可以是在网上,可以炫耀或出售,那就需要全栈式开发 Python。具体如何创建,部署和运行生产 Python Web 应用程序,参考 [Full Stack Python](https://www.oschina.net/action/GoToLink?url=https%
Python 学习之路(四)
Python 学习之路(四) ============== > 以下所用的是Python 3.6 一、时间模块(time 模块) --------------- > 实例环境为Ubuntu 14.04 python 3.6 导入time模块。注:可以在命令行输入: help(time.方法名字)查看帮助文档,例:help(time.localtime)
Python 并行分布式框架之 PP
PP ([Parallel Python](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fwww.parallelpython.com%2F))是基于Python的一个轻量级的,提供在SMP(多处理器或者多核系统)或者集群环境中并行执行Python代码的机制。 最简单和最常见的并行方式
Python中Requests库的高级用法
前面讲了Python的urllib库的使用和方法,Python网络数据采集Urllib库的基本使用 ,Python的urllib高级用法 。 今天我们来学习下Python中Requests库的用法。([官方手册](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fdocs.python-req
Python中文转换报错 'ascii' codec can't decode byte 0xe8 in position
 脚本报错: ![](https://oscimg.oschina.net/oscnet/5b8eaa4be291c9583f3fac05a59733caabf.png) 脚本代码: ![](https://oscimg.oschina.net/oscnet/3bbeff251f60674ece9d67de1e68463fbb1.png) 报错原因:
Python服务器开发一:python基础
Python(蟒蛇)是一种动态解释型的编程语言。Python可以在Windows、UNIX、MAC等多种操作系统上使用,也可以在Java、.NET开发平台上使用。 【特点】 1 Python使用C语言开发,但是Python不再有C语言中的指针等复杂的数据类型。 2 Python具有很强的面向对象特性,而且简化了面向对象的实现。它消除了保护类型、抽象类、
Python资源大全中文版
### 环境管理 管理 Python 版本和环境的工具 * p:非常简单的交互式 python 版本管理工具。[官网](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fqw3rtman%2Fp) * pyenv:简单的 Python 版本管理工具。[官网