- 论坛徽章:
- 0
|
本帖最后由 ccporxy 于 2011-05-23 15:47 编辑
- import sys
- a = 1
- def f():
- a = 2
- def g():
- print(a) #[1]
- frame = sys._getframe()
- code = frame.f_code
- print('Frame global:',frame.f_globals)
- print('Frame locals:',frame.f_locals)
- print('Free variable names:',code.co_freevars)
- print('Cell variable names:', code.co_cellvars)
- print('local variable names:',code.co_varnames)
- return g
- func = f()
- func() #[2]
复制代码
- >>>
- 2
- Frame global: {'a': 1, 'f': <function f at 0x012A8108>, '__builtins__': <module 'builtins' (built-in)>, '__package__': None, 'sys': <module 'sys' (built-in)>, 'func': <function g at 0x0241D1E0>, '__name__': '__main__', '__doc__': None}
- Frame locals: {'a': 2, 'frame': <frame object at 0x02381B18>, 'code': <code object g at 0x023F3570, file "E:/python/name_test.py", line 5>}
- Free variable names: ('a',)
- Cell variable names: ()
- co_nlocals: 2; local variable numbers: 2
- local variable names: ('frame', 'code')
- >>>
复制代码 所谓闭包其实是很容易理解的,还记得python的作用域规则以及名字的搜索规则吗?
最内嵌套作用域规则- 由一个赋值语句引入的名字在这个赋值语句所在的作用域里是可见的,而且在其内部嵌套的每个作用域也是可以见的,除非它被嵌套于内部的,引进同样名字的另一条赋值语句所覆盖。
LEGB:为了找到某个给定名字所引用的对象,首先应该在这个名字的当前作用域查找,如果找到对应的约束(即引用有效),它就是与这个名字相关的活动约束。否则,就应该到直接的外围作用域(名字空间)查找,并继续向外顺序的检查外围作用域,直到达到最外嵌套层次(这个最外嵌套层也就是module自身所定义的那个作用域)。
我们来看看这个实例:
代码【1】处a为2。根据legb规则,此时名称a对应的有效约束即为函数g的外层嵌套域函数f的名字空间,此时与a对应的有效约束为2.
代码【2】处实际上就是闭包的表现。这里func名字对应的有效约束就是函数g的对象。初看上去会让人产生疑问,因为函数f内的约束‘a=2’在其之外应该是不起作用的,当执行func()时,起作用的约束应该是‘a=1’才对。但是python在执行‘func=f()’时,会执行'def g()'语句,这时python会将约束'a=2'与函数g对应的函数对象捆绑在一起(python内部的实现其实是把a=2 这个约束,传给函数g运行时建立栈帧fram对应的代码块的code.co_freevars中。 code.co_freevars:tuple of string),然后将捆绑结果返回。这个捆绑的整体被称为‘闭包’。实际上‘闭包’就是legb规则的一种实现方案。 |
|