python闭包中变量引用分析

企鹅博客
企鹅博客
企鹅博客
25193
文章
0
评论
2020年9月14日 评论 28 views
广告也精彩

标题看起来很虎人,其实不敢称为分析。自己这方面仍有欠缺,以前也许还行,现在专门研究语言的时间和精力没那么多了。有解释的不对的地方欢迎各位来板砖,别误导了大众。

还是直接说这次的问题,今天@neiddy(javaeye)跟我说起闭包的问题,看那几个例子好有意思,想搞懂的冲动。

看两段代码:

>>> def foo():
       a = 1
       def bar():
              a = a +1
              return a
       return bar()
 
>>> foo()
Traceback (most recent call last):
  File "<pyshell#73>", line 1, in <module>
    foo()
  File "<pyshell#72>", line 6, in foo
    return bar()
  File "<pyshell#72>", line 4, in bar
    a = a +1
UnboundLocalError: local variable 'a' referenced before assignment
>>> def foo():
       a = [1]
       def bar():
              a[0] = a[0] + 1
              return a[0]
       return bar()
 
>>> foo()2

通过闭包体验函数式编程,还是不错的感觉。原文下面少了括号,不然返回函数本身就没意思了。再说这个神奇的现象,文中只是说改成容器就ok了,为什么呢?

Google了一些内存管理内存分配的东西,都没有找到出路,走投无路只能投奔源码了。从没看过直接看效率太低,幸好有人总结过了,推荐一下”雨痕 Q.yuhen”的《深入Python编程》,实属低调的大神。

直接闭包部分的代码分析雨痕在闭包的一节有讲到,但是没有专门说这个奇怪的问题的机制。

重复的看书吧,参照了书中的’参数’和’闭包’两节,下面说说根据他的讲解和附上的源码,谈谈我的理解。

雨痕在章节的最后提到”CPython实现闭包的原理并不复杂,说白了就是将所引用的外层对象附加到每次都重新创建的内层函数对象身上 (func_closure)。”

这句话是对前面的概括,同时也包含了重要的信息,就是内部函数对应的对象访问外层函数中的变量其实是通过将外层的变量引用到内存对象的堆栈中来访问的,C语言的代码中时按值传递的。

比如第一段代码中的a,其实是引用了1过来,本身的co_nlocals是1,即一个局部变量是等号前面的a(这样说不太对,只是希望帮助理解这个问题)。既然是局部变量a,a = a +1必然是要抛出UnboundLocalError的。

而对于第二个问题,虽然存在一样的情况,但是即便按值传递,数组中每个位置的指针指向的具体是不变的,还是会修改指定位置的值,因此如果是容器型对象就是可行的。

痛恨自己的就是这个地方总感觉自己说不清楚,其实就是刚学c语言的时候常玩的指针类游戏,虽然说的很烂,但希望指到要害了。接下来就很简单了,按照这个思路来验证一段代码,也就是如果只是输出这个值,不设定局部变量的话那么应该是可以运行的。

>>> def foo():
       a = 1
       def bar():
              return a
       return bar()
 
>>> foo()
1

事情果然跟预想的一样发生了。再细细的体会,好好看看雨痕带着分析的代码吧。了解机制走的更远。Python越来越有意思了,用python的思想写代码,益处良多啊。

By the way,顺带

>>> flist = []
>>> for i in range(3):
       def foo(x): print x + i
       flist.append(foo)
 
>>> for f in flist:
       f(2)
 
4
4
4

文中提到这段代码是因为i不被销毁导致的,今天搜内存分配的时候也看到这个东西。编程的时候应该尽量使用list comprehension减少for和while,一是函数化编程简洁明了,另一方面是性能提升和节省一个计数器。

继续阅读
广告也精彩
初步认识Python中的列表与位运算符 php教程

初步认识Python中的列表与位运算符

Python列表 List(列表) 是 Python 中使用最频繁的数据类型。 列表可以完成大多数集合类的数据结构实现。它支持字符,数字,字符串甚至可以包含列表(所谓嵌套)。 列表用< >标识。是py...
新手python用什么版本好? python教程

新手python用什么版本好?

想学习Python的人都会有一个困惑,那就是Python目前有两个版本Python2和Python3,Python2与Python3有何区别,两个版本该学习哪个好呢? python3 和 python...
python中队列的实现方法(代码示例) python教程

python中队列的实现方法(代码示例)

本篇文章给大家带来的内容是关于python中队列的实现方法(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 对于python来说,要实现一个队列的类根据已经有的方法,是很简...
Python OS模块常用函数说明 python教程

Python OS模块常用函数说明

Python的标准库中的os模块包含普遍的操作系统功能。如果你希望你的程序能够与平台无关的话,这个模块是尤为重要的。即它允许一个程序在编写后不需要任何改动,也不会发生任何问题,就可以在Linux和Wi...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: