1.函数对象

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

秉承着一切皆对象的理念,我们再次回头来看函数(function)。函数也是一个对象,具有属性(可以使用dir()查询)。作为对象,它还可以赋值给其它对象名,或者作为参数传递。

lambda函数

在展开之前,我们先提一下lambda函数。可以利用lambda函数的语法,定义函数。lambda例子如下:

func = lambda x,y: x + y
print func(3,4)

lambda生成一个函数对象。该函数参数为x,y,返回值为x+y。函数对象赋给func。func的调用与正常函数无异。

以上定义可以写成以下形式:

def func(x, y):
return x + y

函数作为参数传递

函数可以作为一个对象,进行参数传递。函数名(比如func)即该对象。比如说:

def test(f, a, b):
print 'test'
print f(a, b) test(func, 3, 5)

test函数的第一个参数f就是一个函数对象。将func传递给f,test中的f()就拥有了func()的功能。

我们因此可以提高程序的灵活性。可以使用上面的test函数,带入不同的函数参数。比如:

test((lambda x,y: x**2 + y), 6, 9)

map()函数

map()是Python的内置函数。它的第一个参数是一个函数对象。

re = map((lambda x: x+3),[1,3,5,6])

这里,map()有两个参数,一个是lambda所定义的函数对象,一个是包含有多个元素的表。map()的功能是将函数对象依次作用于表的每一个元素,每次作用的结果储存于返回的表re中。map通过读入的函数(这里是lambda函数)来操作数据(这里“数据”是表中的每一个元素,“操作”是对每个数据加3)。

在Python 3.X中,map()的返回值是一个循环对象。可以利用list()函数,将该循环对象转换成表。

如果作为参数的函数对象有多个参数,可使用下面的方式,向map()传递函数参数的多个参数:

re = map((lambda x,y: x+y),[1,2,3],[6,7,9])

map()将每次从两个表中分别取出一个元素,带入lambda所定义的函数。

filter()函数

filter函数的第一个参数也是一个函数对象。它也是将作为参数的函数对象作用于多个元素。如果函数对象返回的是True,则该次的元素被储存于返回的表中。filter通过读入的函数来筛选数据。同样,在Python 3.X中,filter返回的不是表,而是循环对象。

filter函数的使用如下例:

def func(a):
if a > 100:
return True
else:
return False print filter(func,[10,56,101,500])

reduce()函数

reduce函数的第一个参数也是函数,但有一个要求,就是这个函数自身能接收两个参数。reduce可以累进地将函数作用于各个参数。如下例:

print reduce((lambda x,y: x+y),[1,2,5,7,9])

reduce的第一个参数是lambda函数,它接收两个参数x,y, 返回x+y。

reduce将表中的前两个元素(1和2)传递给lambda函数,得到3。该返回值(3)将作为lambda函数的第一个参数,而表中的下一个元素(5)作为lambda函数的第二个参数,进行下一次的对lambda函数的调用,得到8。依次调用lambda函数,每次lambda函数的第一个参数是上一次运算结果,而第二个参数为表中的下一个元素,直到表中没有剩余元素。

上面例子,相当于(((1+2)+5)+7)+9

根据mmufhy的提醒: reduce()函数在3.0里面不能直接用的,它被定义在了functools包里面,需要引入包,见评论区。

总结

函数是一个对象

用lambda定义函数

map()

filter()

reduce()

2.闭包(closure)

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

闭包(closure)是函数式编程的重要的语法结构。函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。

不同的语言实现闭包的方式不同。Python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看到Python使用对象来实现一些特殊的语法)。Python一切皆对象,函数这一语法结构也是一个对象。在函数对象中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。

函数对象的作用域

和其他对象一样,函数对象也有其存活的范围,也就是函数对象的作用域。函数对象是使用def语句定义的,函数对象的作用域与def所在的层级相同。比如下面代码,我们在line_conf函数的隶属范围内定义的函数line,就只能在line_conf的隶属范围内调用。

def line_conf():
def line(x):
return 2*x+1
print(line(5)) # within the scope line_conf()
print(line(5)) # out of the scope

line函数定义了一条直线(y = 2x + 1)。可以看到,在line_conf()中可以调用line函数,而在作用域之外调用line将会有下面的错误:

NameError: name 'line' is not defined

说明这时已经在作用域之外。

同样,如果使用lambda定义函数,那么函数对象的作用域与lambda所在的层级相同。

闭包

函数是一个对象,所以可以作为某个函数的返回结果。

def line_conf():
def line(x):
return 2*x+1
return line       # return a function object my_line = line_conf()
print(my_line(5))

上面的代码可以成功运行。line_conf的返回结果被赋给line对象。上面的代码将打印11。

如果line()的定义中引用了外部的变量,会发生什么呢?

def line_conf():
b = 15
def line(x):
return 2*x+b
return line # return a function object b = 5
my_line = line_conf()
print(my_line(5))

我们可以看到,line定义的隶属程序块中引用了高层级的变量b,但b信息存在于line的定义之外 (b的定义并不在line的隶属程序块中)。我们称b为line的环境变量。事实上,line作为line_conf的返回值时,line中已经包括b的取值(尽管b并不隶属于line)。

上面的代码将打印25,也就是说,line所参照的b值是函数对象定义时可供参考的b值,而不是使用时的b值。

一个函数和它的环境变量合在一起,就构成了一个闭包(closure)。在Python中,所谓的闭包是一个包含有环境变量取值的函数对象。环境变量取值被保存在函数对象的__closure__属性中。比如下面的代码:

def line_conf():
b = 15
def line(x):
return 2*x+b
return line # return a function object b = 5
my_line = line_conf()
print(my_line.__closure__)
print(my_line.__closure__[0].cell_contents)

__closure__里包含了一个元组(tuple)。这个元组中的每个元素是cell类型的对象。我们看到第一个cell包含的就是整数15,也就是我们创建闭包时的环境变量b的取值。

下面看一个闭包的实际例子:

def line_conf(a, b):
def line(x):
return ax + b
return line line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5), line2(5))

这个例子中,函数line与环境变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个环境变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用。

如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。利用闭包,我们实际上创建了泛函。line函数定义一种广泛意义的函数。这个函数的一些方面已经确定(必须是直线),但另一些方面(比如a和b参数待定)。随后,我们根据line_conf传递来的参数,通过闭包的形式,将最终函数确定下来。

闭包与并行运算

闭包有效的减少了函数所需定义的参数数目。这对于并行运算来说有重要的意义。在并行运算的环境下,我们可以让每台电脑负责一个函数,然后将一台电脑的输出和下一台电脑的输入串联起来。最终,我们像流水线一样工作,从串联的电脑集群一端输入数据,从另一端输出数据。这样的情境最适合只有一个参数输入的函数。闭包就可以实现这一目的。

并行运算正称为一个热点。这也是函数式编程又热起来的一个重要原因。函数式编程早在1950年代就已经存在,但应用并不广泛。然而,我们上面描述的流水线式的工作并行集群过程,正适合函数式编程。由于函数式编程这一天然优势,越来越多的语言也开始加入对函数式编程范式的支持。

#1楼 2012-12-15 10:11 Chenkun 
写的很好, 不过我觉得还有一个地方应该讲解一下在python2.x中 不能对外层变量赋值:

1
2
3
4
5
6
7
8
9
def line_conf(a, b):
    i = a * b
    def line(x):
        i = i + x
        return i * x + b
    return line
 
line1 = line_conf(4, 5)
print line1(5)

则会报UnboundLocalError错误

#2楼[楼主] 2012-12-15 10:17 Vamei 
@Chenkun
这个我没有注意过。Python 3没有问题么?
#3楼 2012-12-15 10:18 Chenkun 
@Vamei
python3中好像引入了新的关键字nonlocal, 可以解决这个问题!
#4楼 2012-12-15 10:24 Chenkun 
http://www.python.org/dev/peps/pep-3104/
这里有说明和这个问题的一种解决办法!
#5楼 2012-12-15 11:03 zhuangzhuang1988 
python 2.*版本是有问题的.可以这样hack下.
#6楼[楼主] 2012-12-15 11:11 Vamei 
@zhuangzhuang1988
这个方法有些取巧啊
 
#11楼 2013-01-22 16:44 tuzkee 
楼主顺便帮忙解释一下,这几个是啥意思啊?

闭包有什么用:
惰性求值 || 延迟求值 || 在一系列函数调用中保持某个状态

来自:http://www.cnblogs.com/mess4u/archive/2012/10/23/2735468.html

#12楼[楼主] 2013-01-22 22:48 Vamei 
@tuzkee

面向过程的话,是非延迟求值,比如:
a = 5
b = a + 9
c = b - 1
print b
就是要先求a, 再求b,再求c,再求d。想得到最后的结果的话,必须一步步运算并保存中间结果。

而延迟求值是说你可以先设计好整个函数,到最后的时候调用一个函数,并传递给参量,一步求出结果。

在一系列参数中保持某个状态我不太明白,应该是说可以保存函数环境吧。

python 函数对象(函数式编程 lambda、map、filter、reduce)、闭包(closure)的更多相关文章

  1. Python之路Python作用域、匿名函数、函数式编程、map函数、filter函数、reduce函数

    Python之路Python作用域.匿名函数.函数式编程.map函数.filter函数.reduce函数 一.作用域 return 可以返回任意值例子 def test1(): print(" ...

  2. python函数与函数式编程

    https://www.cnblogs.com/evablogs/p/6699515.html 在理解函数式编程之前,我还是对函数的调用,参数传递以及函数的嵌套调用一头雾水,还是花了点时间整理了写思绪 ...

  3. lambda,map,filter,reduce

    lambda 编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数.返回一个函数对象. func = lambda x,y:x+y fu ...

  4. Python之路(第七篇)Python作用域、匿名函数、函数式编程、map函数、filter函数、reduce函数

    一.作用域 return 可以返回任意值例子 def test1(): print("test1") def test(): print("test") ret ...

  5. python学习-day16:函数作用域、匿名函数、函数式编程、map、filter、reduce函数、内置函数r

    一.作用域 作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变 二.匿名函数 lambda:正常和其他函数进行配合使用.正常无需把匿名函数赋值给一个变量. f=lambda x:x*x p ...

  6. Python函数式编程中map()、reduce()和filter()函数的用法

    Python中map().reduce()和filter()三个函数均是应用于序列的内置函数,分别对序列进行遍历.递归计算以及过滤操作.这三个内置函数在实际使用过程中常常和“行内函数”lambda函数 ...

  7. python中的内置函数lambda map filter reduce

    p.p1 { margin: 0; font: 12px "Helvetica Neue" } p.p2 { margin: 0; font: 12px "Helveti ...

  8. python函数 与 函数式编程

    「函数」一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法.在BASIC中叫做subroutine(子过程或子程序), ...

  9. python 函数和函数式编程

    什么是函数 调用函数 创建函数 变长参数 函数式编程 变量的作用域 生成器 1 什么是函数 函数是对程序逻辑进行结构化或过程化的一种编程方法.能将整块代码巧妙地隔离成易于管理 的小块,把重复代码放到函 ...

随机推荐

  1. jmeter随笔(29)-关于自己的jar包和beanshell的使用

    点击标题下「蓝色微信名」可快速关注 坚持的是分享,搬运的是知识,图的是大家的进步,没有收费的培训,没有虚度的吹水,喜欢就关注.转发(免费帮助更多伙伴)等来交流,想了解的知识请留言,给你带来更多价值,是 ...

  2. IIS7.0设置404错误页,返回500状态码

    一般在II6下,设置自定义404错误页时,只需要在错误页中选择自定义的页面,做自己的404页面即可.但是在IIS7.0及以上时,设置完404错误页后,会发现状态码返回的是500,并且可能会引起页面乱码 ...

  3. tesseract-orc 合并识别结果

    在实际使用 tesseract-orc 识别库的时候,初次制作的识别库很有可能识别率不太理想,需要后期慢慢补充 本文演示如何将多个修正过的box文件合并成一个识别库. 首先,需要图片样本.tif文件, ...

  4. Orchard官方文档翻译(五) Dashboard相关

    原文地址:http://docs.orchardproject.net/Documentation/Getting-around-the-dashboard 想要查看文档目录请用力点击这里 最近想要学 ...

  5. python中get、post数据

    方法一:urllib2 参考:http://www.cnblogs.com/chenzehe/archive/2010/08/30/1812995.html post: #!/usr/bin/pyth ...

  6. CODEVS1291 火车线路

    http://codevs.cn/problem/1291/ 题目描述 Description 某列火车行使在C个城市之间(出发的城市编号为1,结束达到的城市的编号为C),假设该列火车有S个座位,现在 ...

  7. Cnetos7下,已经能访问tomcat

    进入/usr/local/apache-tomcat-8.0.24/bin 中 执行:./startup.sh开启tomcat 再执行如下 systemctl stop firewalld.servi ...

  8. word-wrap:break-word和word-break:break-all的小小比较

    个人感觉word-break:break-all;的用法比word-wrap:break-word;要好点, 当然这是出于某些需求而言,下面简单说下word-break:break-all的优点 wo ...

  9. 快速搭建 Node.js 开发环境以及加速 npm

    如何快速搭建 node 开发环境 npm 超慢 github 无法打开的问题 于是我觉得应该写一篇文章解答所有这些起步问题,让新同学也能顺顺利利入门. 快速搭建 Node.js 开发环境 如果你想长期 ...

  10. leetcode 83

    83. Remove Duplicates from Sorted List Given a sorted linked list, delete all duplicates such that e ...