转自:Python函数式编程指南(二):函数
2013-10-22 17:10
465 查看
2. 从函数开始
2.1. 定义一个函数如下定义了一个求和函数:
使用lambda可以定义简单的单行匿名函数。lambda的语法是:
2.2. 使用函数赋值
事实上你已经见过了,上一节中我们将lambda表达式赋值给了add。同样,使用def定义的函数也可以赋值,相当于为函数取了一个别名,并且可以使用这个别名调用函数:
2.3. 闭包
闭包是一类特殊的函数。如果一个函数定义在另一个函数的作用域中,并且函数中引用了外部函数的局部变量,那么这个函数就是一个闭包。下面的代码定义了一个闭包:
如果需要在函数中修改全局变量,可以使用关键字global修饰变量名。Python 2.x中没有关键字为在闭包中修改外部变量提供支持,在3.x中,关键字nonlocal可以做到这一点:
由于使用了函数体外定义的变量,看起来闭包似乎违反了函数式风格的规则即不依赖外部状态。但是由于闭包绑定的是外部函数的局部变量,而一旦离开外部函数作用域,这些局部变量将无法再从外部访问;另外闭包还有一个重要的特性,每次执行至闭包定义处时都会构造一个新的闭包,这个特性使得旧的闭包绑定的变量不会随第二次调用外部函数而更改。所以闭包实际上不会被外部状态影响,完全符合函数式风格的要求。(这里有一个特例,Python 3.x中,如果同一个作用域中定义了两个闭包,由于可以修改外部变量,他们可以相互影响。)
虽然闭包只有在作为参数和返回值时才能发挥它的真正威力,但闭包的支持仍然大大提升了生产率。
2.4. 作为参数
如果你对OOP的模板方法模式很熟悉,相信你能很快速地学会将函数当作参数传递。两者大体是一致的,只是在这里,我们传递的是函数本身而不再是实现了某个接口的对象。
我们先来给前面定义的求和函数add热热身:
言归正传。我们的客户有一个从0到4的列表:
首先可以预见的是求和这个动作是非常常见的,如果我们把这个动作抽象成一个单独的函数,以后需要对另一个列表求和时,就不必再写一遍这个套路了:
1. 使用初始值与列表的第一个元素相加;
2. 使用上一次相加的结果与列表的下一个元素相加;
3. 重复第二步,直到列表中没有更多元素;
4. 将最后一次相加的结果返回。
如果现在需要求乘积,我们可以写出类似的流程——只需要把相加换成相乘就可以了:
虽然有模板方法这样的设计模式,但那样的复杂度往往使人们更情愿到处编写循环。将函数作为参数完全避开了模板方法的复杂度。
Python有一个内建函数reduce,完整实现并扩展了reduce_的功能。本文稍后的部分包含了有用的内建函数的介绍。请注意我们的目的是没有循环,使用函数替代循环是函数式风格区别于指令式风格的最显而易见的特征。
*像Python这样构建于类C语言之上的函数式语言,由于语言本身提供了编写循环代码的能力,内置函数虽然提供函数式编程的接口,但一般在内部还是使用循环实现的。同样的,如果发现内建函数无法满足你的循环需求,不妨也封装它,并提供一个接口。
2.5. 作为返回值
将函数返回通常需要与闭包一起使用(即返回一个闭包)才能发挥威力。我们先看一个函数的定义:
这里我们先略过map_的蹩脚实现而只关注它的功能。对于上一节中的lst,你可能发现最后求乘积结果始终是0,因为lst中包含了0。为了让结果看起来足够大,我们来使用map_为lst中的每个元素加1:
现在回头看看我们写的两个lambda表达式:相似度超过90%,绝对可以使用抄袭来形容。而问题不在于抄袭,在于多写了很多字符有木有?如果有一个函数,根据你指定的左操作数,能生成一个加法函数,用起来就像这样:
另外一个特殊的例子是装饰器。装饰器用于增强甚至干脆改变原函数的功能,我曾写过一篇文档介绍装饰器,地址在这里:/article/5268067.html。
*题外话,单就例子中的这个功能而言,在一些其他的函数式语言中(例如Scala)可以使用名为柯里化(Currying)的技术实现得更优雅。柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。如下的伪代码所示:
2.6. 部分内建函数介绍
reduce(function, iterable[, initializer])
这个函数的主要功能与我们定义的reduce_相同。需要补充两点:
它的第二个参数可以是任何可迭代的对象(实现了__iter__()方法的对象);
如果不指定第三个参数,则第一次调用function将使用iterable的前两个元素作为参数。
由reduce和一些常见的function组合成了下面列出来的内置函数:
这个函数的主要功能与我们定义的map_相同。需要补充一点:
map还可以接受多个iterable作为参数,在第n次调用function时,将使用iterable1
, iterable2
, ...作为参数。
filter(function, iterable)
这个函数的功能是过滤出iterable中所有以元素自身作为参数调用function时返回True或bool(返回值)为True的元素并以列表返回,与系列第一篇中的my_filter函数相同。
zip(iterable1, iterable2, ...)
这个函数返回一个列表,每个元素都是一个元组,包含(iterable1
, iterable2
, ...)。
例如:zip([1, 2], [3, 4]) --> [(1, 3), (2, 4)]
如果参数的长度不一致,将在最短的序列结束时结束;如果不提供参数,将返回空列表。
除此之外,你还可以使用本文2.5节中提到的functools.partial()为这些内置函数创建常用的偏函数。
另外,pypi上有一个名为functional的模块,除了这些内建函数外,还额外提供了更多的有意思的函数。但由于使用的场合并不多,并且需要额外安装,在本文中就不介绍了。但我仍然推荐大家下载这个模块的纯Python实现的源代码看看,开阔思维嘛。里面的函数都非常短,源文件总共只有300行不到,地址在这里:http://pypi.python.org/pypi/functional
此篇结束:)
转自:/article/5268070.html
相关文章推荐
- Python函数式编程指南(二):函数
- python 学习笔记---函数式编程之高阶函数
- Python进阶学习笔记——函数式编程之高阶函数
- python函数式编程之匿名函数、装饰器、偏函数
- python3 第二十一章 - 函数式编程之return函数和闭包
- 【python学习笔记】函数式编程:返回函数
- Python的函数式编程-传入函数、排序算法、函数作为返回值、匿名函数、偏函数、装饰器
- Python的函数以及函数式编程
- python函数之二 函数式编程
- Python基础学习代码之函数和函数式编程
- 【Python学习笔记】函数式编程:偏函数
- python 函数、函数式编程、变量作用域、函数__doc__属性
- 11 函数和函数式编程 - 《Python 核心编程》
- Python入门 第四天(函数式编程、map、reduce、filter、排序函数、函数返回函数、闭包、匿名函数lambda)
- Python学习笔记11:Python函数和函数式编程
- Learning Python 012 函数式编程 2 返回函数 匿名函数 装饰器 偏函数
- [Python]函数式编程的4个常用内建函数
- Python函数式编程指南:目录和参考(转载)
- 【语言工具】Python闭包,装饰器,生成器,偏函数,函数式编程,lamda,map,reduce,filter
- Python函数式编程指南:目录和参考