在这篇文章里,你将学会什么是函数范式以及如何应用Python进行函数式编程。你也将理解列表推导和其它模式的推导。
函数范式
在命令式范式中,通过为计算机提供一系列指令而后执行它们来实现工作。在执行这些指令时,能够扭转某些状态。例如,假如你最后将A设置为5,而后更改A的值。这时在变量外部值的意义上,你扭转了A的状态。
在函数式范式中,你不必通知计算机做什么而是通知他这个货色是什么。比方数字的最大公约数是什么,从1到n的乘积是什么等等。
因而,变量不能变动。一旦你设置了一个变量,它就永远放弃这种状态(留神,在纯函数式语言中,它们不是变量)。因而,函数式编程没有副作用。副作用指的是函数扭转它本人以外的货色。让咱们看一些典型Python代码的示例:
这段代码的输入是5。在函数式范式中,扭转变量是一个很大的禁忌,并且具备影响其范畴之外事物的性能也是一个很大的禁忌。函数惟一能做的就是计算一些货色并将其作为后果返回。
当初你可能会想:“没有变量,没有副作用?为什么这样好?“这个问题问得好,我置信大多数人对此感到纳闷。
如果应用雷同的参数调用函数两次,则保障返回雷同的后果。如果你曾经学习了数学函数,你就会晓得这个益处。这称为参照透明度。因为函数没有副作用,如果你正在构建一个计算某些事件的程序,你能够减速程序。如果每次调用func(2)都返回3,咱们能够将它存储在表中,这能够避免程序反复运行雷同的性能。
通常,在函数式编程中,咱们不应用循环。咱们应用递归。递归是一个数学概念,通常意味着“自我调用”。应用递归函数,该函数将其本身作为子函数反复调用。这是Python中递归函数的一个很好的例子:
有些编程语言也具备惰性。这意味着他们直到最初一秒才计算或做任何事件。如果你编写一些代码来执行2 + 2,函数程序只会在你真正须要应用后果时计算出来。咱们很快就会在Python中摸索惰性。
Map
为了了解,咱们先来看看迭代是什么。通常能够迭代的对象是列表或数组,但Python有许多不同的类型能够迭代。你甚至能够创立本人的对象,这些对象能够通过实现魔术办法进行迭代。魔术办法就像是一个API,能够帮忙你的对象变得更加Pythonic。您须要实现2个魔术办法能力使对象成为可迭代的:
第一个魔术办法“\_\_iter\_\_”(注:这里是双下划线)返回迭代对象,这通常在循环开始时应用。”\_\_next\_\_“返回下一个对象。
让咱们疾速进入一个终端调用下面的代码:
运行将会打印出
在Python中,迭代器是一个只有\_\_iter\_\_魔术办法的对象。这意味着您能够拜访对象中的地位,但不能遍历该对象。一些对象将具备魔术办法\_\_next\_\_而不是\_\_iter\_\_魔术办法,例如汇合(在本文前面探讨)。对于本文,咱们假如咱们接触的所有内容都是可迭代的对象。
当初咱们晓得什么是可迭代对象了,让咱们回到map函数。 map函数容许咱们将函数利用于iterable中的每一项。 Map须要2个输出,它们别离是要利用的函数和可迭代对象。
假如咱们有一个数字列表,如下所示:
咱们想要对每个数字进行平方,咱们能够编写如下代码:
Python中函数式的函数是具备惰性的。如果咱们不应用“list”,该函数将存储iterable的定义,而不是列表自身。咱们须要明确通知Python“把它变成一个列表”供咱们应用。
在Python中忽然从非惰性求值转向惰性求值有点奇怪。如果你在函数式思维形式中思考得更多,而不是命令式思维形式,那么你最终会习惯它。
当初写一个像“square(num)”这样的一般函数尽管很好,但却是不对的。咱们必须定义一个残缺的函数能力在map中应用它?好吧,咱们能够应用lambda(匿名)函数在map中定义一个函数。
Lambda表达式
lambda表达式是一个只有一行的函数。举个例子,这个lambda表达式对给定的数字进行平方:
让咱们运行它:
这看起来不像一个函数吗?
嗯,这有点令人困惑,但能够解释。咱们将一些货色调配给变量“square”。那这个呢:
通知Python这是一个lambda函数,输出叫做x。冒号之后的任何内容都是您对输出所做的操作,它会主动返回后果。
简化咱们的square程序到只有一行代码,咱们能够这样做:
所以在lambda表达式中,所有参数都在右边,你要用它们做的货色在左边。它有点乱。但事实是,编写只有其余函数式程序员能力浏览的代码会有肯定的乐趣。此外,应用一个函数并将其转换为一行代码是十分酷的。
Reduce
Reduce是一个将迭代变成一个货色的函数。通常,你能够在列表上应用reduce函数执行计算以将其缩小到一个数字。 Reduce看起来像这样:
咱们常常会应用lambda表达式作为函数。
列表的乘积是每个独自的数字相乘。要做到这一点你将编写如下代码:
然而应用reduce你能够这样写:
取得雷同的性能,代码更短,并且在应用函数式编程的状况下更整洁。(注:reduce函数在Python3中已不是内置函数,须要从functools模块中导入)
Filter
filter函数采纳可迭代的形式,并过滤掉你在该可迭代中不须要的所有内容。
通常,filter须要一个函数和一个列表。它将函数利用于列表中的每一项,如果该函数返回True,则不执行任何操作。如果返回False,则从列表中删除该项。
语法如下:
让咱们看一个小例子,没有filter咱们会写:
应用filter,能够这样写:
Python作为一门一直倒退与遍及的语言,还在不断更新中。在学习时,倡议找一些学习搭档一起来学习和探讨,成果更佳。如果想学习Python,欢送退出Python学习交换群(627012464),一起督促,一起学习。外面有开发工具,很多干货和技术材料分享!
高阶函数
高阶函数能够将函数作为参数并返回函数。一个非常简单的例子如下:
第二个返回函数的例子:
结尾我说过纯函数式编程语言没有变量。更高阶的函数使这变得更容易。
Python中的所有函数都是一等公民。一等公民被定义为具备以下一个或多个特色:
在运行时创立
在数据结构中调配变量或元素
作为函数的参数传递
作为函数的后果返回
Python中的所有函数都能够用作高阶函数。
Partial application
Partial application(也称为闭包)有点奇怪,但十分酷。您能够在不提供所需的所有参数的状况下调用函数。让咱们在一个例子中看到这一点。咱们想要创立一个函数,它承受2个参数,一个基数和一个指数,并返回指数幂的基数,如下所示:
当初咱们想要一个专用的平方函数,应用幂函数计算出数字的平方:
这无效,但如果咱们想要一个立方体性能呢?或者求四次方的性能呢?咱们能够持续写下它们吗?好吧,你能够。但程序员很懒的。如果你一遍又一遍地反复同样的事件,这表明有一种更快的办法来加快速度,这将使你不再反复。咱们能够在这里应用闭包。让咱们看一个应用闭包的square函数的示例:
是不是很酷!咱们能够只应用1个参数来调用须要2个参数的函数。
咱们还能够应用一个循环来生成一个幂函数,该函数实现从立方体始终到1000的幂。
函数式编程不是pythonic
您可能曾经留神到了,咱们想要在函数式编程中做的很多事件都围绕着列表。除了reduce函数和闭包之外,您看到的所有函数都会生成列表。 Guido(Python之父)不喜爱Python中的函数式,因为Python曾经有了本人生成列表的办法。
如果你在Python的交互环境下写入”import this“,你将会失去:
这是Python之禅。这是一首对于Pythonic意味着什么的诗。咱们想要波及的局部是:
There should be one — and preferably only one — obvious way to do it.(应该尽量找到一种,最好是惟一一种显著的解决方案)
在Python中,map和filter能够执行与列表推导(上面探讨)雷同的操作。这突破了Python之禅的一个规定,因而函数式编程的这些局部不被视为“pythonic”。
另一个话题是Lambda。在Python中,lambda函数是一个一般函数。 Lambda是语法糖。这两种说法是等价的。
一般函数能够执行lambda函数能够执行的所有操作,但它不能以相同的形式工作。 lambda函数不能实现一般函数能够执行的所有操作。
这是一个简短的论证,为什么函数式编程不能很好地适应整个Python生态系统。你可能曾经留神到我之前提到了列表推导,咱们当初将探讨它们。
列表推导
后面,我提到过你能够用map或filter做的任何事件,你能够用列表推导。列表推导是一种在Python中生成列表的办法。语法是:
让咱们对列表中的每个数字进行平方,例如:
咱们能够看到如何将函数利用于列表中的每一项。咱们如何利用filter呢?看看后面的代码:
咱们能够将其转换成一个列表推导,像这样:
列表反对if这样的语句。您不再须要将一百万个函数利用于某些货色以取得您想要的货色。事实上,如果你想尝试生成某种列表,那么应用列表推导看起来会更清晰,更容易。如果咱们想要将列表中每个0以下的数字平方怎么办?有了lambda,map和filter你会写:
这仿佛很长很简单。通过列表推导,它只是:
列表推导仅实用于列表。map,filter适宜任何可迭代的对象,那么这有什么用呢?你能够对你遇到的任何可迭代对象应用任何推导。
其余推导
你能够为任何可迭代对象创立一个推导。
能够应用推导生成任何可迭代的对象。从Python 2.7开始,您甚至能够生成字典(hashmap)。
如果它是可迭代的,则能够生成它。让咱们看一下最初一组的例子。
set是一个元素列表,在该列表中没有元素反复两次。
set中的元素没有程序。
您可能会留神到set(汇合)与dict(字典)具备雷同的花括号。 Python十分聪慧。依据你是否为dict提供值,它会晓得你是在写dict推导还是set推导。
总结
函数式编程好看而纯正。函数式代码能够很洁净,但也可能很乱。一些Python程序员不喜爱Python中的函数式编程。但我认为,你应该在解决问题时,应用最佳工具。
本文转自 https://juejin.cn/post/7043656047721971720,如有侵权,请分割删除。