简单讲解Python中的闭包


Posted in Python onAugust 11, 2015

闭包并不是什么新奇的概念,它早在高级语言开始发展的年代就产生了。闭包(Closure)是词法闭包(Lexical Closure)的简称。对闭包的具体定义有很多种说法,这些说法大体可以分为两类:
一种说法认为闭包是符合一定条件的函数,比如参考资源中这样定义闭包:闭包是在其词法上下文中引用了自由变量的函数。
另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。比如参考资源中就有这样的的定义:在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。

就像这样:

#python 中的闭包
... def func(data):
...   count = [data]
...   def wrap():
...     count[0] += 1
...     return count[0]
...   return wrap
... 
... a = func(1)
>>> a()
5: 2
>>> a()
6: 3

 def func(x):
...   return lambda y :y+x
>>> b = func(1)
>>> b(1)
7: 2
>>> b(2)
8: 3
>>> print b #这里b是个function 在ruby中是proc
<function <lambda> at 0x01AC68F0>


 def addx(x):
... def adder (y): return x + y
... return adder
>>> add8 = addx(8)
>>> add8(8)
9: 16

简单说,闭包就是根据不同的配置信息得到不同的结果

python实例
看概念总是让人摸不着头脑,看几个python小例子就会了

例1

def make_adder(addend):
  def adder(augend):
    return augend + addend
  return adder

p = make_adder(23)
q = make_adder(44)

print p(100)
print q(100)

运行结果:

123
144

分析一下:
我们发现,make_adder是一个函数,包括一个参数addend,比较特殊的地方是这个函数里面又定义了一个新函数,这个新函数里面的一个变量正好是外部make_adder的参数.也就是说,外部传递过来的addend参数已经和adder函数绑定到一起了,形成了一个新函数,我们可以把addend看做新函数的一个配置信息,配置信息不同,函数的功能就不一样了,也就是能得到定制之后的函数.

再看看运行结果,我们发现,虽然p和q都是make_adder生成的,但是因为配置参数不同,后面再执行相同参数的函数后得到了不同的结果.这就是闭包.

例2

def hellocounter (name):
  count=[0] 
  def counter():
    count[0]+=1
    print 'Hello,',name,',',str(count[0])+' access!'
  return counter

hello = hellocounter('ma6174')
hello()
hello()
hello()

执行结果

Hello, ysisl , 1 access!
Hello, ysisl , 2 access!
Hello, ysisl , 3 access!

分析一下
这个程序比较有趣,我们可以把这个程序看做统计一个函数调用次数的函数.count[0]可以看做一个计数器,没执行一次hello函数,count[0]的值就加1。也许你会有疑问:为什么不直接写count而用一个列表?这是python2的一个bug,如果不用列表的话,会报这样一个错误:

UnboundLocalError: local variable 'count' referenced before assignment.

什么意思?就是说conut这个变量你没有定义就直接引用了,我不知道这是个什么东西,程序就崩溃了.于是,再python3里面,引入了一个关键字:nonlocal,这个关键字是干什么的?就是告诉python程序,我的这个count变量是再外部定义的,你去外面找吧.然后python就去外层函数找,然后就找到了count=0这个定义和赋值,程序就能正常执行了.

python3 代码

def hellocounter (name):
  count=0 
  def counter():
    nonlocal count
    count+=1
    print 'Hello,',name,',',str(count[0])+' access!'
  return counter

hello = hellocounter('ma6174')
hello()
hello()
hello()

例3

def makebold(fn):
  def wrapped():
    return "<b>" + fn() + "</b>"
  return wrapped

def makeitalic(fn):
  def wrapped():
    return "<i>" + fn() + "</i>"
  return wrapped

@makebold
@makeitalic
def hello():
  return "hello world"

print hello()

执行结果

<b><i>hello world</i></b>

简单分析
怎么样?这个程序熟悉吗?这不是传说的的装饰器吗?对,这就是装饰器,其实,装饰器就是一种闭包,我们再回想一下装饰器的概念:对函数(参数,返回值等)进行加工处理,生成一个功能增强版的一个函数。再看看闭包的概念,这个增强版的函数不就是我们配置之后的函数吗?区别在于,装饰器的参数是一个函数或类,专门对类或函数进行加工处理。

python里面的好多高级功能,比如装饰器,生成器,列表推到,闭包,匿名函数等,开发中用一下,可能会达到事半功倍的效果!

Python 相关文章推荐
python实现删除文件与目录的方法
Nov 10 Python
python实现读Excel写入.txt的方法
Apr 29 Python
Python提取特定时间段内数据的方法实例
Apr 01 Python
python 一个figure上显示多个图像的实例
Jul 08 Python
wxPython实现分隔窗口
Nov 19 Python
python用opencv完成图像分割并进行目标物的提取
May 25 Python
Keras 利用sklearn的ROC-AUC建立评价函数详解
Jun 15 Python
scrapy框架携带cookie访问淘宝购物车功能的实现代码
Jul 07 Python
如何快速理解python的垃圾回收机制
Sep 01 Python
python生成xml时规定dtd实例方法
Sep 21 Python
Prometheus开发中间件Exporter过程详解
Nov 30 Python
Pandas数据分析的一些常用小技巧
Feb 07 Python
Python实现短网址ShortUrl的Hash运算实例讲解
Aug 10 #Python
python实现web方式logview的方法
Aug 10 #Python
python实现JAVA源代码从ANSI到UTF-8的批量转换方法
Aug 10 #Python
python用10行代码实现对黄色图片的检测功能
Aug 10 #Python
详解Python中dict与set的使用
Aug 10 #Python
分析并输出Python代码依赖的库的实现代码
Aug 09 #Python
python根据京东商品url获取产品价格
Aug 09 #Python
You might like
php去掉字符串的最后一个字符附substr()的用法
2011/03/23 PHP
php中选择什么接口(mysql、mysqli)访问mysql
2013/02/06 PHP
微信公众平台实现获取用户OpenID的方法
2015/04/15 PHP
Yii2.0表关联查询实例分析
2016/07/18 PHP
PHP简单实现数字分页功能示例
2016/08/24 PHP
javascript支持firefox,ie7页面布局拖拽效果代码
2007/12/20 Javascript
prototype Element学习笔记(篇二)
2008/10/26 Javascript
解决jquery操作checkbox火狐下第二次无法勾选问题
2014/02/10 Javascript
Js实现滚动变色的文字效果
2014/06/16 Javascript
JavaScript函数定义的常见注意事项小结
2014/09/16 Javascript
javascript限制用户只能输汉字中文的方法
2014/11/20 Javascript
jQuery实现鼠标滚轮动态改变样式或效果
2015/01/05 Javascript
理解AngularJs指令
2015/12/10 Javascript
基于jQuery实现以手风琴方式展开和折叠导航菜单
2016/01/28 Javascript
总结JavaScript的正则与其他语言的不同之处
2016/08/25 Javascript
JQuery通过后台获取数据遍历到前台的方法
2018/08/13 jQuery
[01:53]2016完美“圣”典风云人物:Maybe专访
2016/12/05 DOTA
[02:37]2018DOTA2亚洲邀请赛赛前采访-EG篇
2018/04/03 DOTA
[40:03]Liquid vs Optic 2018国际邀请赛淘汰赛BO3 第一场 8.21
2018/08/22 DOTA
python使用WMI检测windows系统信息、硬盘信息、网卡信息的方法
2015/05/15 Python
详解Python中的from..import绝对导入语句
2016/06/21 Python
python斐波那契数列的计算方法
2018/09/27 Python
对Python使用mfcc的两种方式详解
2019/01/09 Python
Python分支语句与循环语句应用实例分析
2019/05/07 Python
wxpython自定义下拉列表框过程图解
2020/02/14 Python
波兰补充商店:Muscle Power
2018/10/29 全球购物
写clone()方法时,通常都有一行代码,是什么?
2012/10/31 面试题
学校岗位设置方案
2014/01/16 职场文书
收银员的岗位职责范本
2014/02/04 职场文书
个人现实表现材料
2014/02/04 职场文书
财务主管岗位职责
2014/02/28 职场文书
事业单位绩效考核实施方案
2014/03/27 职场文书
历史学专业求职信
2014/06/19 职场文书
公司领导班子召开党的群众路线教育实践活动总结大会新闻稿
2014/10/21 职场文书
格列佛游记读书笔记
2015/06/30 职场文书
2019班干部竞选演讲稿范本!
2019/07/08 职场文书