当前位置:  开发笔记 > 编程语言 > 正文

与语言X闭包相比,Python中的闭包有哪些限制?

如何解决《与语言X闭包相比,Python中的闭包有哪些限制?》经验,为你挑选了3个好方法。

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 () ()

通常只是指出函数有自己的局部变量就足以阻止这种愚蠢.



1> Thomas Woute..:

目前,最重要的限制是您无法分配外部范围变量.换句话说,闭包是只读的:

>>> 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__`的内部类也可以解决它(但带有列表的版本更简洁).

2> John Milliki..:

我看到人们遇到Python的唯一困难就是当他们尝试将非功能性功能(如变量重新分配和闭包)混合在一起时,如果这不起作用,我会感到惊讶:

def outer ():
    x = 1
    def inner ():
        print x
        x = 2
    return inner
outer () ()

通常只是指出函数有自己的局部变量就足以阻止这种愚蠢.


@Moe谢谢; @JF完全正确.闭包的工作方式与任何其他函数一样,但出于某种原因,人们认为在分配变量时它们应该具有魔力.

3> mykhal..:

与Javascript闭包相比,Python闭包的限制(或"限制")是它不能用于有效的数据隐藏

使用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

蟒蛇

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]


即使使用标准OO数据隐藏,您也可以使用obj._Class__private_variable访问Python类'__private_variable.数据隐藏的目的是提供抽象,而不是安全性,如果你的客户端代码倾向于破坏戳.
推荐阅读
TXCWB_523
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有