与X语言closures相比,Python有什么限制?
其中X是支持某些闭包的编程语言(C#,Javascript,Lisp,Perl,Ruby,Scheme等)。
Python中的闭包 (与Ruby的闭包相比)中提到了一些限制,但是这篇文章比较陈旧,在现代Python中还不存在很多限制。
看到一个具体限制的代码示例将是很好的。
相关问题 :
- 你能解释闭包(与Python有关)吗?
- 什么是“closures”?
- javascriptclosures如何工作?
目前最重要的限制是你不能分配给外部variables。 换句话说,闭包是只读的:
>>> def outer(x): ... def inner_reads(): ... # Will return outer's 'x'. ... return x ... def inner_writes(y): ... # Will assign to a local 'x', not the outer 'x' ... x = y ... def inner_error(y): ... # Will produce an error: 'x' is local because of the assignment, ... # but we use it before it is assigned to. ... tmp = x ... x = y ... return tmp ... return inner_reads, inner_writes, inner_error ... >>> inner_reads, inner_writes, inner_error = outer(5) >>> inner_reads() 5 >>> inner_writes(10) >>> inner_reads() 5 >>> inner_error(10) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 11, in inner_error UnboundLocalError: local variable 'x' referenced before assignment
除非另外声明,否则在本地范围(函数)中分配的名称始终是本地名称。 虽然有“全局”声明来声明一个variables的全局variables,即使它被赋值,也没有这样的封闭variables的声明。 在Python 3.0中,有(将是)“nonlocal”声明就是这样做的。
您可以通过使用可变的容器types来同时解决此限制:
>>> def outer(x): ... x = [x] ... def inner_reads(): ... # Will return outer's x's first (and only) element. ... return x[0] ... def inner_writes(y): ... # Will look up outer's x, then mutate it. ... x[0] = y ... def inner_error(y): ... # Will now work, because 'x' is not assigned to, just referenced. ... tmp = x[0] ... x[0] = y ... return tmp ... return inner_reads, inner_writes, inner_error ... >>> inner_reads, inner_writes, inner_error = outer(5) >>> inner_reads() 5 >>> inner_writes(10) >>> inner_reads() 10 >>> inner_error(15) 10 >>> inner_reads() 15
我看到人们遇到的唯一困难就是当他们试图将非function特性(如variables重新分配和闭包)混合在一起时,并且在这种情况下无法工作时感到惊讶:
def outer (): x = 1 def inner (): print x x = 2 return inner outer () ()
通常只是指出一个函数有自己的局部variables就足以阻止这种愚蠢的行为。
与Javascriptclosures相比,Pythonclosures的一个限制(或“限制”)是它不能用于有效的数据隐藏
使用Javascript
var mksecretmaker = function(){ var secrets = []; var mksecret = function() { secrets.push(Math.random()) } return mksecret } var secretmaker = mksecretmaker(); secretmaker(); secretmaker() // privately generated secret number list // is practically inaccessible
python
import random def mksecretmaker(): secrets = [] def mksecret(): secrets.append(random.random()) return mksecret secretmaker = mksecretmaker() secretmaker(); secretmaker() # "secrets" are easily accessible, # it's difficult to hide something in Python: secretmaker.__closure__[0].cell_contents # -> eg [0.680752847190161, 0.9068475951742101]
在Python 3中通过nonlocal
语句修复:
nonlocal
语句会导致列出的标识符引用最近包含范围(不包括全局variables)的先前绑定variables。 这很重要,因为绑定的默认行为是首先search本地名称空间。 该语句允许封装代码除了全局(模块)作用域之外还重新绑定局部作用域之外的variables。
约翰·米利肯
def outer(): x = 1 # local to `outer()` def inner(): x = 2 # local to `inner()` print(x) x = 3 return x def inner2(): nonlocal x print(x) # local to `outer()` x = 4 # change `x`, it is not local to `inner2()` return x x = 5 # local to `outer()` return (inner, inner2) for inner in outer(): print(inner()) # -> 2 3 5 4
@Kevin Little的回答包括代码示例的评论
nonlocal
并不能完全解决python3.0上的这个问题:
x = 0 # global x def outer(): x = 1 # local to `outer` def inner(): global x x = 2 # change global print(x) x = 3 # change global return x def inner2(): ## nonlocal x # can't use `nonlocal` here print(x) # prints global ## x = 4 # can't change `x` here return x x = 5 return (inner, inner2) for inner in outer(): print(inner()) # -> 2 3 3 3
另一方面:
x = 0 def outer(): x = 1 # local to `outer` def inner(): ## global x x = 2 print(x) # local to `inner` x = 3 return x def inner2(): nonlocal x print(x) x = 4 # local to `outer` return x x = 5 return (inner, inner2) for inner in outer(): print(inner()) # -> 2 3 5 4
它适用于python3.1-3.3
直到3.0的更好的解决方法是将variables作为缺省参数包含在所包含的函数定义中:
def f() x = 5 def g(y,z,x = x): x = x + 1