Python闭包详解
添加时间:2013-7-23 点击量:
Python闭包详解
1 快速预览
以下是一段简单的闭包代码示例:
def foo():
m=3
n=5
def bar():
a=4
return m+n+a
return bar
>>>bar = foo()
>>>bar()
12
申明:
bar在foo函数的代码块中定义。我们称bar是foo的内部函数。
在bar的局部感化域中可以直接接见foo局部感化域中定义的m、n变量。
简单的说,这种内部函数可以应用外部函数变量的行动,就叫闭包。
那么闭包内部是如何来实现的呢?
我们一步步来,先看两个python内置的object: <code>和<cell>
2 code object
code object是python代码经过编译后的对象。
它用来存储一些与代码有关的信息以及bytecode。
以下代码示例,演示了如何经由过程编译产生code object
以及应用exec运行该代码,和应用dis便利地查看字节码。
code object还有很多的特点可以接见。具体请看官方文档。
import dis
code_obj = compile(sum([1,2,3]), , single)
>>>exec(code_obj)
6
>>> dis.dis(code_obj)
1 0 LOAD_NAME 0 (sum)
3 LOAD_CT 0 (1)
6 LOAD_CT 1 (2)
9 LOAD_CT 2 (3)
12 BUILD_LIST 3
15 CALL_FUNCTION 1
18 PRINT_EXPR
19 LOAD_CT 3 (None)
22 RETURN_VALUE
那么,这跟我们的例子有什么关系?
>>> foo.func_code
<code object foo at 01FE92F0, file <pyshell#50>, line 1>
我们可以看到,函数定义好之后,就可以经由过程[函数名.func_code]
接见该函数的code object,之后我们会用到它的一些特点。
3 cell object
cell对象的引入,是为了实现被多个感化域引用的变量。
对每一个如许的变量,都用一个cell对象来保存 其值 。
拿之前的示例来说,m和n既在foo函数的感化域中被引用,又在bar
函数的感化域中被引用,所以m, n引用的值,都邑在一个cell对象中。
可以经由过程内部函数的__closure__或者func_closure特点查看cell对象:
>>> bar = foo()
>>> bar.__closure__
(<cell at 0 x01FE8DF0: int object at 0 x0186D888>, <cell at 0 x01F694B0: int object at 0 x0186D870>)
这两个int型的cell分别存储了m和n的值。
无论是在外部函数中定义,还是在内部函数中调用,引用的指向都是cell对象中的值。
注:内部函数无法批改cell对象中的值,若是测验测验批改m的值,编译器会认为m是函数
bar的局部变量,同时foo代码块中的m也会被认为是函数foo的局部变量,就会再把m
认作闭包变量,两个m分别在各自的感化域下起感化。1
4 闭包解析
- 应用dis2模块解析foo的bytecode。
2 0 LOAD_CT 1 (3)
3 STORE_DEREF 0 (m)
3 6 LOAD_CT 2 (5)
9 STORE_DEREF 1 (n)
4 12 LOAD_CLOSURE 0 (m)
15 LOAD_CLOSURE 1 (n)
18 BUILD_TUPLE 2
21 LOAD_CT 3 (<code object bar at 018D9848, file <pyshell#1>, line 4>)
24 MAKE_CLOSURE 0
27 STORE_FAST 0 (bar)
7 30 LOAD_FAST 0 (bar)
33 RETURN_VALUE
进行逐行解析:
LOAD_CT 1 (3) :
将foo.func_code.co_consts [1]
的值3压入栈
STORE_DEREF 0 (m) :
从栈顶Pop出3包装成cell对象存入cell与变量的存储区的第0槽。
创建变量m引用该cell对象。
LOAD_CLOSURE 0 (m) :
将m的引用信息压入栈,类似如下信息:
<cell at 0 x01D572B0: int object at 0 x0180D6F8>
并将变量名m记入func_code.cellvars [0]
。
LOAD_CLOSURE 1 (n) :
同上
栈区状况:
1原来,再大的房子,再大的床,没有相爱的人陪伴,都只是冰冷的物质。而如果身边有爱人陪伴,即使房子小,床小,也觉得无关紧要,因为这些物质上面有了爱的温度,成了家的元素。—— 何珞《婚房》#书摘#
Python闭包详解
1 快速预览
以下是一段简单的闭包代码示例:
def foo():
m=3
n=5
def bar():
a=4
return m+n+a
return bar
>>>bar = foo()
>>>bar()
12
申明:
bar在foo函数的代码块中定义。我们称bar是foo的内部函数。
在bar的局部感化域中可以直接接见foo局部感化域中定义的m、n变量。
简单的说,这种内部函数可以应用外部函数变量的行动,就叫闭包。
那么闭包内部是如何来实现的呢?
我们一步步来,先看两个python内置的object: <code>和<cell>
2 code object
code object是python代码经过编译后的对象。
它用来存储一些与代码有关的信息以及bytecode。
以下代码示例,演示了如何经由过程编译产生code object
以及应用exec运行该代码,和应用dis便利地查看字节码。
code object还有很多的特点可以接见。具体请看官方文档。
import dis
code_obj = compile(sum([1,2,3]), , single)
>>>exec(code_obj)
6
>>> dis.dis(code_obj)
1 0 LOAD_NAME 0 (sum)
3 LOAD_CT 0 (1)
6 LOAD_CT 1 (2)
9 LOAD_CT 2 (3)
12 BUILD_LIST 3
15 CALL_FUNCTION 1
18 PRINT_EXPR
19 LOAD_CT 3 (None)
22 RETURN_VALUE
那么,这跟我们的例子有什么关系?
>>> foo.func_code
<code object foo at 01FE92F0, file <pyshell#50>, line 1>
我们可以看到,函数定义好之后,就可以经由过程[函数名.func_code]
接见该函数的code object,之后我们会用到它的一些特点。
3 cell object
cell对象的引入,是为了实现被多个感化域引用的变量。
对每一个如许的变量,都用一个cell对象来保存 其值 。
拿之前的示例来说,m和n既在foo函数的感化域中被引用,又在bar
函数的感化域中被引用,所以m, n引用的值,都邑在一个cell对象中。
可以经由过程内部函数的__closure__或者func_closure特点查看cell对象:
>>> bar = foo()
>>> bar.__closure__
(<cell at 0 x01FE8DF0: int object at 0 x0186D888>, <cell at 0 x01F694B0: int object at 0 x0186D870>)
这两个int型的cell分别存储了m和n的值。
无论是在外部函数中定义,还是在内部函数中调用,引用的指向都是cell对象中的值。
注:内部函数无法批改cell对象中的值,若是测验测验批改m的值,编译器会认为m是函数
bar的局部变量,同时foo代码块中的m也会被认为是函数foo的局部变量,就会再把m
认作闭包变量,两个m分别在各自的感化域下起感化。1
4 闭包解析
- 应用dis2模块解析foo的bytecode。
2 0 LOAD_CT 1 (3)
3 STORE_DEREF 0 (m)
3 6 LOAD_CT 2 (5)
9 STORE_DEREF 1 (n)
4 12 LOAD_CLOSURE 0 (m)
15 LOAD_CLOSURE 1 (n)
18 BUILD_TUPLE 2
21 LOAD_CT 3 (<code object bar at 018D9848, file <pyshell#1>, line 4>)
24 MAKE_CLOSURE 0
27 STORE_FAST 0 (bar)
7 30 LOAD_FAST 0 (bar)
33 RETURN_VALUE
进行逐行解析:
LOAD_CT 1 (3) :
将foo.func_code.co_consts [1]
的值3压入栈
STORE_DEREF 0 (m) :
从栈顶Pop出3包装成cell对象存入cell与变量的存储区的第0槽。
创建变量m引用该cell对象。
LOAD_CLOSURE 0 (m) :
将m的引用信息压入栈,类似如下信息:
<cell at 0 x01D572B0: int object at 0 x0180D6F8>
并将变量名m记入func_code.cellvars [0]
。
LOAD_CLOSURE 1 (n) :
同上
栈区状况:
1原来,再大的房子,再大的床,没有相爱的人陪伴,都只是冰冷的物质。而如果身边有爱人陪伴,即使房子小,床小,也觉得无关紧要,因为这些物质上面有了爱的温度,成了家的元素。—— 何珞《婚房》#书摘# |