简单讲解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 打印对象的所有属性值的方法
Sep 11 Python
Python使用迭代器捕获Generator返回值的方法
Apr 05 Python
基于python select.select模块通信的实例讲解
Sep 21 Python
python中模块的__all__属性详解
Oct 26 Python
Python可变参数*args和**kwargs用法实例小结
Apr 27 Python
解决Django 在ForeignKey中出现 non-nullable field错误的问题
Aug 06 Python
Anaconda3+tensorflow2.0.0+PyCharm安装与环境搭建(图文)
Feb 18 Python
Python拼接字符串的7种方式详解
Mar 19 Python
python+selenium+Chrome options参数的使用
Mar 18 Python
Python加速程序运行的方法
Jul 29 Python
python中Pyqt5使用Qlabel标签播放视频
Apr 22 Python
python playwrigh框架入门安装使用
Jul 23 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
如何过滤高亮显示非法字符
2006/10/09 PHP
windows下zendframework项目环境搭建(通过命令行配置)
2012/12/06 PHP
php使用qr生成二维码的示例分享
2014/01/20 PHP
PHP合并静态文件详解
2014/11/14 PHP
php实现的美国50个州选择列表实例
2015/04/20 PHP
java script编程起步(第三课)
2007/01/10 Javascript
js获取控件位置以及不同浏览器中的差别介绍
2013/08/08 Javascript
浅析Cookie中的Path与domain
2013/12/18 Javascript
JavaScript插件化开发教程 (一)
2015/01/27 Javascript
基于jQuery实现左右图片轮播(原理通用)
2015/12/24 Javascript
ionic由于使用了header和subheader导致被遮挡的问题的两种解决方法
2016/09/22 Javascript
浅谈javascript中的三种弹窗
2016/10/21 Javascript
bootstrap实现动态进度条效果
2017/03/08 Javascript
vue.js全局API之nextTick全面解析
2017/07/07 Javascript
Spring boot 和Vue开发中CORS跨域问题解决
2018/09/05 Javascript
JS动态图片的实现方法完整示例
2020/01/13 Javascript
koa2的中间件功能及应用示例
2020/03/05 Javascript
vue 移动端记录页面浏览位置的方法
2020/03/11 Javascript
python单例模式实例分析
2015/04/08 Python
python处理xml文件的方法小结
2017/05/02 Python
Python-Tkinter Text输入内容在界面显示的实例
2019/07/12 Python
详解pytorch tensor和ndarray转换相关总结
2020/09/03 Python
Python使用xpath实现图片爬取
2020/09/16 Python
使用纯 CSS 创作一个脉动 loader效果的源码
2018/09/28 HTML / CSS
借助HTML5 Canvas API制作一个简单的猜字游戏
2016/03/25 HTML / CSS
英国Amara家居法国网站:家居装饰,现代装饰和豪华礼品
2016/12/15 全球购物
英国独特的时尚和生活方式品牌:JOY
2018/03/17 全球购物
英国奢侈皮具品牌:Aspinal of London
2018/09/02 全球购物
汽车工程专业应届生求职信
2013/10/19 职场文书
上课迟到检讨书
2014/02/19 职场文书
招聘专员岗位职责
2014/03/07 职场文书
考核工作实施方案
2014/03/30 职场文书
工作经验交流材料
2014/12/30 职场文书
给老婆道歉的话
2015/01/20 职场文书
十二月早安励志心语大全
2019/12/03 职场文书
使用 Apache Dubbo 实现远程通信(微服务架构)
2022/02/12 Servers