您的位置:首页 > 科技 > 名人名企 > 如何用十分钟学会函数式 Python?

如何用十分钟学会函数式 Python?

2018-09-22 来源:CSDN  浏览:    关键词:python,python函数,迭代计算,迭代模型

函数式编程到底是什么?本文将详解其概念,同时分享怎样在 Python 中使用函数式编程。

主要内容包括列表解析式和其他形式的解析式。

在命令式模型中,执行程序的方式是给计算机一系列指令让它执行。

执行过程中计算机会改变状态。

例如,比如 A 的初始值是 5,后来改变了 A 的值。

那么 A 就是个变量,而变量的意思就是包含的值会改变。

而在函数式模式中,你不需要告诉计算机做什么,而是告诉计算机是什么。

比如数字的最大公约数是什么,1 到 n 的乘积是什么等等。

因此,变量是不能被改变的。

变量一旦被设置,就永远保持同一个值(注意在纯粹的函数式语言中,它们不叫变量)。

因此,在函数式模型中,函数没有副作用。

副作用就是函数对函数外的世界做出的改变。

来看看下面这段Python代码的例子:代码的输出是 5。

在函数式模型中,改变变量的值是完全不允许的,让函数影响函数外的世界也是不允许的。

函数唯一能做的就是做一些计算然后返回一个值。

你可能会想:“没有变量也没有副作用?这有什么好的?”好问题。

如果函数使用同样的参数调用两次,那么我们可以保证它会返回同样的结果。

如果你学过数学函数,你肯定知道这样做的好。

这叫做引用透明性(referential transparency)。

由于函数没有副作用,那么我们可以加速计算某个东西的程序。

比如,如果程序知道 func(2)返回 3,那么可以将这个值保存在表中,这样就不需要重复运行我们早已知道结果的函数了。

通常,函数式编程不使用循环,而是使用递归。

递归是个数学概念,通常的意思是“把结果作为自己的输入”。

使用递归函数,函数可以反复调用自己。

下面就是个使用Python定义的递归函数的例子:函数式编程语言也是懒惰的。

懒惰的意思是,除非到最后一刻,否则它们不会执行计算或做任何操作。

如果代码要求计算2 2,那么函数式程序只有在真正用到计算结果的时候才会去计算。

我们马上就会介绍Python中的这种懒惰。

要理解映射(map),首先需要理解什么是可迭代对象。

可迭代对象(iterable)指任何可以迭代的东西。

通常是列表或数组,但 Python 还有许多其他可迭代对象。

甚至可以自定义对象,通过实现特定的魔术方法使其变成可迭代对象。

魔术方法就像 API 一样,能让对象更有 Python 风格。

要让对象变成可迭代对象,需要实现以下两个魔术方法:第一个魔术方法“__iter__”(双下划线iter)返回迭代子,通常在循环开始时调用。

__next__则返回迭代的下一个对象。

可以打开命令行试一下下面的代码:在 Python 中,迭代器就是只实现了__iter__魔术方法的对象。

也就是说,你可以访问对象中都包含的位置,但无法遍历整个对象。

一些对象实现了__next__魔术方法,但没有实现__iter__魔术方法,比如集合(本文稍后会讨论)。

在本文中,我们假设涉及到的一切对象都是可迭代的对象。

现在我们知道了什么是可迭代的对象,回过头来讨论下映射函数。

映射可以对可迭代对象中的每个元素执行指定的函数。

通常,我们对列表中的每个元素执行函数,但要知道映射其实可以针对绝大多数可迭代对象使用。

假设有一个列表由以下数字组成:我们希望得到每个数字的平方,那么代码可以写成这样:Python中的函数式函数是懒惰的。

如果我们不加“list()”,那么函数只会将可迭代对象保存下来,而不会保存结果的列表。

我们需要明确地告诉Python“把它转换成列表”才能得到结果。

在Python中一下子从不懒惰的函数求值转换到懒惰的函数似乎有点不适应。

但如果你能用函数式的思维而不是过程式的思维,那么最终会适应的。

这个“square(num)”的确不错,但总觉得有点不对劲。

难道为了仅使用一次的map就得定义整个函数吗?其实我们可以使用lambda函数(匿名函数)。

Lambda表达式就是只有一行的函数。

比如下面这个lambda表达式可以求出给定数字的平方:你肯定在问:“参数去哪儿了?这究竟是啥意思?看起来根本不像函数啊?”嗯,的确是不太容易懂……但还是应该能够理解的。

我们上面的代码把什么东西赋给了变量“square”。

就是这个东西:它告诉Python这是个lambda函数,输入的名字为x。

冒号后面的一切都是对输入的操作,然后它会自动返回操作的结果。

这样我们的求平方的代码可以简化成一行:有了lambda表达式,所有参数都放在左边,操作都放在右边。

虽然看上去有点乱,但不能否认它的作用。

实际上能写出只有懂得函数式编程的人才能看懂的代码还是有点小兴奋的。

而且把函数变成一行也非常酷。

归纳(reduce)是个函数,它把一个可迭代对象变成一个东西。

通常,我们在列表上进行计算,将列表归纳成一个数字。

归纳的代码看起来长这样:上面的函数可以使用lambda表达式。

列表的乘积就是把所有数字乘到一起。

可以这样写代码:但使用归纳,可以写成这样:这样能得到同样的结果。

这段代码更短,而且借助函数式编程,这段代码更简洁。

过滤(filter)函数接收一个可迭代对象,然后过滤掉对象中一切不需要的东西。

通常过滤接收一个函数和一个列表。

它会针对列表中的每个元素执行函数,如果函数返回True,则什么都不做。

如果函数返回False,则从列表中去掉那个元素。

我们来看一个简单的例子。

没有过滤,代码要写成这样:使用过滤可以写成这样:高阶函数接收函数作为参数,返回另一个函数。

一个非常简单的例子如下所示:或者更简单“返回函数”的例子:还记得之前说过函数式编程语言没有变量吗?实际上高阶函数能很容易做到这一点。

如果你只需要在一系列函数中传递数据,那么数据根本不需要保存到变量中。

Python 中的所有函数都是顶级对象。

顶级对象是拥有一个或多个以下特征的对象:在运行时生成赋值给某个数据结构中的变量或元素作为参数传递给函数作为函数的结果返回所以,所有 Python 中的函数都是对象,都可以用作高阶函数。

部分函数有点难懂,但非常酷。

通过它,你不需要提供完整的参数就能调用函数。

我们来看个例子。

我们要创建一个函数,它接收两个参数,一个是底,另一个是指数,然后返回底的指数次幂,代码如下:现在我们需要一个求平方的函数,可以这么写:这段代码没问题,但如果需要立方函数怎么办?或者四次方函数呢?是不是得一直定义新的函数?这样做也行,但是程序员总是很懒的。

如果需要经常重复一件事情,那就意味着一定有办法提高速度,避免重复。

我们可以用部分函数实现这一点。

下面是使用部分函数求平方的例子:这是不是很苦?我们事先告诉 Python 第二个参数,这样只需要提供一个参数就能调用需要两个参数的函数了。

还可以使用循环来生成直到能计算 1000 次方的所有函数。

函数式编程不够 Python你也许注意到了,我们这里许多函数式编程都用到了列表。

除了归纳和部分函数之外,所有其他函数都生成列表。

Guido(Python发明人)不喜欢在 Python 中使用函数式的东西,因为 Python 有自己的方法来生成列表。

这就是Python之禅。

这首诗表明了什么叫做Python风格。

我们要指出的是这句话:

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:service@qeerd.com,投稿邮箱:tougao@qeerd.com