什么是闭包?
闭包(closure)是词法闭包(lexical closure)的简称。闭包不是新奇的概念,而是早在高级程序语言开始发展的年代就已产生。
对闭包的理解大致分为两类,将闭包视为函数或者是由函数及其引用环境组成的复合体。
- 前者认为闭包是在其词法上下文中引用了自动变量的函数。
- 后者认为闭包是显示表示引用外部环境,并将它与函数捆绑在一起而产生的复合体。
所谓的*变量是指局部变量以外的变量,同时*变量的绑定可预知,所谓的绑定(binding)是指变量名称与其所代表的对象之间的联系。一些早期的计算机语言没有所谓封闭的函数,*变量在运行时再进行绑定。对于那些拥有开放和封闭函数概念的计算机语言,人们需要一种新的术语来区分这两种函数,于是便有了术语闭包。
一般而言,第二种观点相对更为准确。因为函数是一些可执行的代码,这些代码在定义函数时被固化,在运行时不会发生任何变化,所以一个函数只有一个实例。而闭包会随着引用环境变化而产生不同的实例。
在 Python 以及大多数现代计算机语言中,所有函数都是封闭的,也就是说没有*变量。于是对闭包的定义也从早期”对包含可预知绑定对象的*变量的函数“变成了”可引用非激活环境的对象的函数“。对 Python 而言,*变量被绑定到在外围作用域定义的变量。
Closure in Python
闭包(closure)是一种引用了外部变量的函数对象,无论该变量所处的作用域是否还存在于内存中。
举例来说,函数 generate_power_func 返回了另一个函数:
def generate_power_func(n):
print "id(n): %X" % id(n)
def nth_power(x):
return x**n
print "id(nth_power): %X" % id(nth_power)
return nth_power
函数 nth_power 就是一个闭包,它可以访问定义在 generate_power_func 函数中的变量 n,显而易见如果缺少变量 n,函数 nth_power 将是一个不能执行的没有闭合的函数,这个不完整的函数 nth_power 需要变量 n 来让它变成一个完整的函数对象,这种函数就是闭包,换句话说是变量 n 封闭了函数 nth_power。
现在我们调用一下函数 generate_power_func,并将调用结果返回给一个变量 raised_to_4。
>>> raised_to_4 = generate_power_func(4)
id(n): 28F8A4
id(nth_power): B6CB4570
>>> repr(rasied_to_4)
'<function nth_power at 0xb6cb4570>'
结果是调用函数 generate_power_func(4) 将生成一个 nth_power 函数对象。现在我们将函数 generate_power_func 函数从全局命名空间删除。
>>> del generate_power_func
然后调用闭包函数 raised_to_4。
>>> rasied_to_4(2)
16
奇迹出现了,销毁函数 generate_power_func 并没有影响到函数 raised_to_4。我们在函数 generate_power_func 中定义变量 n,并且我们已经销毁了函数 generate_power_func,为什么 raised_to_4 会知道变量 n=4?
这是因为函数对象 nth_power 是由 generate_power_func 产生的一个闭包,闭包会保留来自外围作用域变量的信息。
__closure__ 属性和 cell 对象
Python 中函数对象都拥有一个 __closure__ 属性。
__closure__ 对象返回一个由 cell 对象组成的元组,cell 对象记录了定义在外围作用域的变量信息。
>>> raised_to_4.__closure__
(<cell at 0xb6cb7f70: int object at 0x28f8a4>,)
>>> type(raised_to_4.__closure__[0])
<type 'cell'>
>>> raised_to_4.__closure__[0].cell_contents
4
正如所见,__closure__ 属性引用了一个 int 对象,这个 int 对象就是变量 n。对于那些不是闭包的函数对象来说,__closure__ 属性值为 None。
Ref:
Python Closures Explained
Closures in Python
闭包的概念、形式与应用
Python 闭包的更多相关文章
-
Python闭包与函数对象
1. Python闭包是什么 在python中有函数闭包的概念,这个概念是什么意思呢,查看Wikipedia的说明如下: “ In programming languages, closures (a ...
-
Python闭包及装饰器
Python闭包 先看一个例子: def outer(x): def inner(y): return x+y return innder add = outer(8) print add(6) 我们 ...
-
Python闭包详解
Python闭包详解 1 快速预览 以下是一段简单的闭包代码示例: def foo(): m=3 n=5 def bar(): a=4 return m+n+a return bar >> ...
-
Python闭包及其作用域
Python闭包及其作用域 关于Python作用域的知识在python作用域有相应的笔记,这个笔记是关于Python闭包及其作用域的详细的笔记 如果在一个内部函数里,对一个外部作用域(但不是全局作用域 ...
-
Python 闭包小记
闭包就是能够读取其他函数内部变量的函数.例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“.在本质上,闭包是将函数内部和函数外部连接起来 ...
-
理解Python闭包概念
闭包并不只是一个python中的概念,在函数式编程语言中应用较为广泛.理解python中的闭包一方面是能够正确的使用闭包,另一方面可以好好体会和思考闭包的设计思想. 1.概念介绍 首先看一下维基上对闭 ...
-
Python闭包举例
Python闭包的条件: 1.函数嵌套.在外部函数内,定义内部函数. 2.参数传递.外部函数的局部变量,作为内部函数参数. 3.返回函数.外部函数的返回值,为内部函数. 举例如下: def line_ ...
-
python 闭包和装饰器
python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...
-
Python 闭包(Closure)
Python 闭包 (Closure) 这里介绍一下python 的闭包 基本概念 闭包(closure)是函数式编程的重要的语法结构. 函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函 ...
随机推荐
-
[学习笔记]JS中闭包的理解
一.闭包概念的理解 闭包,又称为词法闭包或函数闭包指引用了*变量的函数.这个被引用的*变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外. *变量:该变量既不是函数本身定义的也不是函数 ...
-
DOM--2 创建可重用的对象
对象中包含的 分类(内置对象: 注意这些都是function:除了Function对象,实例都是object) Function对象 Function实例function 构造函数的function ...
-
获取全国市以及地理坐标,各大坐标系北斗,百度,WGS-84坐标系的转换,有图,有代码
1 先上坐标取到的值: 获取到的坐标部分如下: '北京市':[116.39564503788,39.92998577808], '天津市':[117.21081309155,39.1439299033 ...
-
怎么设置 mysql 多主复制
更新 其实本文主要来自www.digitalocean.com ,但是我没有买他们家的 VPS 用来 demo 了.只是用vagrant 来模拟了. 介绍 说说关于通过两台 vps 来扩展 mysql ...
-
C# 和 Unix 时间戳转换
unix时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒. /// 时间戳转为C#格式时间 private DateTime GetTime(string timeSt ...
-
yum命令学习
yum配置文件 /etc/yum.conf yum check-update检查一下有无更新 每天都要(设置定时任务todo) 1.列出所有可更新的软件清单---yum check-update 2. ...
-
linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数(转载)
一,进程终止有5种方式: 正常退出: 从main函数返回 调用exit 调用_exit 异常退出: 调用abort 由信号终止 二,exit和_exit区别: 关于_exit(): #include ...
-
java与C++变量初始化的对比
java尽力保证:所有变量在使用前都能得到恰当的初始化 ①函数/方法局部变量的初始化 在C/C++中,变量的初始化还是得依赖于程序员的自觉性.对于函数局部变量,编译器不会为基本类型赋予默认初始值,新手 ...
-
WEB页面异步调用场景测试
在我们测试异步调用前,我们首先弄清楚异步调用到底是什么? 异步调用的定义:一个可以无需等待被调用函数的返回值就让操作继续进行的方法, 举一个形象的例子就是:领导给A分配了一个任务, 然后领导就干其他事 ...
-
typeScript 学习
最近看了下typescript, 虽然说已经有很多人已经用到它了,但是我还是写写自己的feel咯:这里推荐学习链接 https://ts.xcatliu.com. 这个入门学习,我不好做评价,但是我自 ...