递归闭包中的范围错误

发布于 2024-08-26 22:34:10 字数 646 浏览 8 评论 0原文

为什么这有效:

def function1():                                                                                                             
       a = 10                                                                                                                    
       def function2():
          print a
       function2()

但这不起作用:

def function1():
    a = 10
    def function2():
        print a
        a -= 1
        if a>0:
           function2()
    function2()

我收到此错误:

UnboundLocalError: local variable 'a' referenced before assignment

why does this work:

def function1():                                                                                                             
       a = 10                                                                                                                    
       def function2():
          print a
       function2()

but this does not:

def function1():
    a = 10
    def function2():
        print a
        a -= 1
        if a>0:
           function2()
    function2()

I get this error:

UnboundLocalError: local variable 'a' referenced before assignment

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

心头的小情儿 2024-09-02 22:34:10

该错误似乎并不能很好地描述根本问题。迈克解释了这些消息,但没有解释根本原因。

实际的问题是在 python 中你不能分配给封闭变量。所以在 function2 中 'a' 是只读的。当您分配给它时,您创建了一个新变量,正如迈克指出的那样,您在写入之前先读取该变量。

如果你想从内部作用域分配给外部变量,你必须像这样作弊:

def function1():
    al = [10]
    def function2():
        print al[0]
        al[0] -= 1
        if al[0]>0:
           function2()
    function2()

所以 al 是不可变的,但它的内容不是,你可以在不创建新变量的情况下更改它们。

The error doesn't seem to be very descriptive of the root problem. Mike explains the messages but that does not explain the root cause.

The actual problem is that in python you cannot assign to closed over variables. So in function2 'a' is read only. When you assign to it you create a new variable which, as Mike points out, you read before you write.

If you want to assign to the to the outer variable from the inner scope you have to cheat like so:

def function1():
    al = [10]
    def function2():
        print al[0]
        al[0] -= 1
        if al[0]>0:
           function2()
    function2()

So al is immutable but its contents are not and you can change them without creating a new variable.

旧街凉风 2024-09-02 22:34:10

需要注意的是,这是 Python 中的一个语法错误。 Python 本身(在字节码级别)可以很好地分配给这些变量; 2.x 中根本没有语法来表明您想要这样做。它假设如果您分配给嵌套级别中的变量,则意味着它是该变量的本地变量。

这是一个很大的缺点;能够分配给闭包是基础。我已经用 charlieb's hack 多次解决了这个问题。

Python 3 使用名称非常尴尬的“nonlocal”关键字修复了这个问题:

def function1():
    a = 10
    def function2():
        nonlocal a
        print(a)
        a -= 1
        if a>0:
           function2()
    function2()
function1()

很糟糕的是,这种语法仅在 3.x 中可用;大多数人都停留在 2.x 中,并且不得不继续使用 hack 来解决这个问题。这迫切需要向后移植到 2.x。

http://www.python.org/dev/peps/pep-3104/

It should be noted that this is a syntax glitch in Python. Python itself (at the bytecode level) can assign to these variables just fine; there's simply no syntax in 2.x to indicate that you want to do so. It assumes that if you assign to a variable in a nesting level, you mean for it to be a local to it.

This is a huge shortcoming; being able to assign to closures is fundamental. I've worked around this with charlieb's hack several times.

Python 3 fixes this with the very awkwardly-named "nonlocal" keyword:

def function1():
    a = 10
    def function2():
        nonlocal a
        print(a)
        a -= 1
        if a>0:
           function2()
    function2()
function1()

It's very poor that this syntax is only available in 3.x; most people are stuck in 2.x, and have to continue using hacks to work around this problem. This badly needs to be backported to 2.x.

http://www.python.org/dev/peps/pep-3104/

蔚蓝源自深海 2024-09-02 22:34:10

在非工作代码段中,当您说“a -= 1”时,您将分配给 a。因此,在 function2 内部,a 是该作用域的本地变量,而不是封闭的作用域。 Python 的闭包是词法的 - 它不会在 function2 的框架中动态查找 a,如果尚未分配,则在 function1 中查找它代码> 的框架。

请注意,这根本不依赖于递归性或使用闭包。考虑一下这个函数的例子

def foo():
    print a
    a = 4

,调用它也会给你带来一个UnboundLocalError。 (如果没有 a = 4,它将使用全局 a,或者如果没有,则引发 NameError。)因为 a 可能在该范围内分配,它是本地的。


如果我正在设计这个函数,我可能会使用类似的方法

def function1():
    a = 10
    def function2(a=a):
        print a
        a -= 1
        if a > 0:
           function2(a)
    function2()

(或者当然 for a in xrange(10, -1, -1): print a ;-) )

In the non-working snippet, you assign to a when you say "a -= 1". Because of that, inside function2, a is local to that scope, not taken the enclosing scope. Python's closures are lexical—it does not dynamically look for a in function2's frame and if it has not been assigned go and look for it in function1's frame.

Note that this doesn't depend on the recursiveness or using closures at all. Consider the example of this function

def foo():
    print a
    a = 4

Calling it will get you an UnboundLocalError too. (Without a = 4 it would either use the global a or, if there isn't one, raise a NameError.) Because a is potentially assigned within that scope, it is local.


If I was designing this function, I might use an approach more like

def function1():
    a = 10
    def function2(a=a):
        print a
        a -= 1
        if a > 0:
           function2(a)
    function2()

(or of course for a in xrange(10, -1, -1): print a ;-) )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文