X是任何支持某种闭包风格的编程语言(C#,Javascript,Lisp,Perl,Ruby,Scheme等).
Python中的Closures中提到了一些限制(与Ruby的闭包相比),但文章很旧,现代Python中不再存在许多限制.
查看具体限制的代码示例会很棒.
相关问题:
你能解释一下闭包(因为它们与Python有关)吗?
什么是'关闭'?
javascript闭包是如何工作的?
Thomas Woute.. 44
目前,最重要的限制是您无法分配外部范围变量.换句话说,闭包是只读的:
>>> 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 "", line 1, in File " ", line 11, in inner_error UnboundLocalError: local variable 'x' referenced before assignment
除非另有声明,否则在本地范围(函数)中分配的名称始终是本地的.虽然有一个'全局'声明来声明一个变量全局,即使它被赋值,但是封闭变量没有这样的声明 - 但是.在Python 3.0中,有(将是)'非本地'声明就是这样做的.
您可以使用可变容器类型同时解决此限制:
>>> 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
当你想到的`nonlocal`解决了这个问题.带有`__call__`的内部类也可以解决它(但带有列表的版本更简洁). (7认同)
John Milliki.. 6
我看到人们遇到Python的唯一困难就是当他们尝试将非功能性功能(如变量重新分配和闭包)混合在一起时,如果这不起作用,我会感到惊讶:
def outer (): x = 1 def inner (): print x x = 2 return inner outer () ()
通常只是指出函数有自己的局部变量就足以阻止这种愚蠢.
目前,最重要的限制是您无法分配外部范围变量.换句话说,闭包是只读的:
>>> 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 "", line 1, in File " ", line 11, in inner_error UnboundLocalError: local variable 'x' referenced before assignment
除非另有声明,否则在本地范围(函数)中分配的名称始终是本地的.虽然有一个'全局'声明来声明一个变量全局,即使它被赋值,但是封闭变量没有这样的声明 - 但是.在Python 3.0中,有(将是)'非本地'声明就是这样做的.
您可以使用可变容器类型同时解决此限制:
>>> 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
我看到人们遇到Python的唯一困难就是当他们尝试将非功能性功能(如变量重新分配和闭包)混合在一起时,如果这不起作用,我会感到惊讶:
def outer (): x = 1 def inner (): print x x = 2 return inner outer () ()
通常只是指出函数有自己的局部变量就足以阻止这种愚蠢.
与Javascript闭包相比,Python闭包的限制(或"限制")是它不能用于有效的数据隐藏
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
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 # -> e.g. [0.680752847190161, 0.9068475951742101]