前两天写了一篇文章,讲了一下Python的闭包。刚好今天又看到一个小问题,和Python闭包有点相关。顺手记录下来。
如下一段代码,
funcs = []
for i in xrange(10):
def bar(n):
return n + i
funcs.append(bar)
print funcs[3](5)
这段代码中,我们期望得到的结果是3+5为8。但是实际得到的结果是什么呢?是14。
14是怎么来的?
反汇编看看:
7 0 LOAD_FAST 0 (n)
3 LOAD_GLOBAL 0 (i)
6 BINARY_ADD
7 RETURN_VALUE
注意i是global。
得到14的原因就是,funcs[3]这个函数对象获取i的值,是在执行的时候。而i的作用域是global。也就是说,当这个func开始执行的时候,i已经变成9了。那么结果当然等于14了。
从这个结果看,以上代码和下面代码效果是等价的。
funcs = []
for i in xrange(10):
pass
def bar(n):
return n + i
funcs.append(bar)#这句重复10遍
print funcs[3](5)
很无趣吧。那么考虑一下,如果把i丢到闭包来做会怎样?
funcs = []
def foo(m):
for i in xrange(m):
def bar(n):
return n + i
funcs.append(bar)
foo(10)
print funcs[3](5)
很遗憾,结果依然是14.
反汇编代码如下:
9 0 LOAD_FAST 0 (n)
3 LOAD_DEREF 0 (i)
6 BINARY_ADD
7 RETURN_VALUE
唉,只是傻傻的远程访问而已。
“所有的bar代码中,i仅仅只是在closure中的一个引用而已。指向的依然是同一个对象。当这个对象被改变,所有的bar执行的时候获得的值都是修改后的值”。
顺手写了一段JavaScript来测试,发现结果是一样的。也是会全局改变。具体代码如下:
但是用haskell实现了一个,完全符合预期的结果。
main = do
let funcs = [(\n -> n + i) | i <- [1..10] ]
let x : xs = funcs
return (x 4)
返回结果是5。
看来Python对FP的支持还是比不上Haskell这种正统的函数式语言。
个人觉得如果Python要发展FP的话,可以考虑如下解决方案:区别本地变量和闭包变量。当声明函数的时候将闭包变量拷贝一份到本地,同时保留指向原闭包对象的引用。在搜索名字的时候,始终都是先搜索本地变量,再搜索本地闭包变量副本,再搜索全局变量。当需要修改的时候,如果是本地变量就直接修改。如果是闭包变量的时候,将原来闭包真正指向的对象进行修改,同时覆盖掉本地的闭包副本。
这个方法只是暂时的考虑,没有仔细的推敲。乍看之下似乎可以解决问题。
不过,Python毕竟是OO的语言。没有Haskell或者Lisp那种天生的作用域的控制能力。唉。那就用OO的方式来搞Python把。
分享到:
相关推荐
第6章和第7章深入介绍了高级Python编程概念,如迭代器、闭包、装饰器、生成器。对异常处理的良好和深入的了解,使我们能够编写出可靠和健壮的代码。为了满足这一需要,第8章介绍了Python中异常处理的突出特点。第9章...
Python + NumPy程序的可组合转换:区分,矢量化,JIT到GPU / TPU,以及更多JAX:Autograd和XLA 转型| 安装指南| 神经网络库| 变更记录| 参考文档| ...它可以通过循环,分支,递归和闭包来区分,并且可以用d
它可以通过循环,分支,递归和闭包来区分,并且可以采用派生类的派生类。 它支持通过反向模式区分(aka反向传播)以及正向模式区分,并且两者可以任意组合为任意顺序。 新功能是JAX使用在GPU和TPU上编译和运行您的...
计算机视觉和模式识别(CVPR)的研究,2006年6月,纽约 该存储库还包含在Levin,Anat,Dani Lischinski和Yair Weiss中提出的背景/前景重建方法的实现。 “自然图像抠像的封闭形式解决方案。” IEEE Transactions on ...
JAX 是 Autograd 和 XLA,结合起来用于高性能机器学习研究。 借助 Autograd 的更新版本,JAX 可以自动区分原生 Python 和 NumPy 函数。 它可以通过循环、分支、递归和闭包进行微分,并且可以取导数的导数的导数。...
对TBC特征矩阵进行平移极差变换,利用指数切比雪夫距离法构建了模糊相似矩阵,采用模糊聚类中的传递闭包法构建进化树。该方法不需要多序列比对,计算简单。对两组基因组序列构建进化树,实验结果验证了该方法的有效...
是一个序列建模工具包,允许研究人员和开发人员为翻译、摘要、语言建模和其他文本生成任务训练自定义模型。 ) [ - 预测知识图中概念之间的链接的开源 Python 库。) [(PBG)是一个分布式系统,用于学习大型图的图...
我们研究了双字母组语言的后缀替换闭包。 2021年2月12日星期五 我们讨论了双语法例和语言。 我们讨论了精确度和冗余度的数学符号。 对于星期一,请阅读第4单元的最高2.3节(最高64页) 我们将在星期一讨论SL2...
支持,据我当前的研究,不同线程必须有各自的runtime对象,每个runtime可以有多个环境(context),同一个runtime下的多个环境可以自由交换数据,但环境之间不共享数据。也就是说api级别可以把环境1的数据带到环境2...