递归闭包中的作用域错误

Rug*_*rra 9 python recursion closures scope

为什么这样做:

def function1():                                                                                                             
       a = 10                                                                                                                    
       def function2():
          print a
       function2()
Run Code Online (Sandbox Code Playgroud)

但这不是:

def function1():
    a = 10
    def function2():
        print a
        a -= 1
        if a>0:
           function2()
    function2()
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

UnboundLocalError: local variable 'a' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

cha*_*ieb 14

该错误似乎不是对根本问题的描述.迈克解释了这些消息,但这并没有解释根本原因.

实际问题是在python中你不能分配给已关闭的变量.所以在function2中'a'是只读的.当你分配给它时,你创建一个新的变量,正如迈克指出的那样,你在写之前就读过了.

如果你想从内部范围分配到外部变量,你必须像这样作弊:

def function1():
    al = [10]
    def function2():
        print al[0]
        al[0] -= 1
        if al[0]>0:
           function2()
    function2()
Run Code Online (Sandbox Code Playgroud)

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

  • 实际上,这是设计此功能的关键点 - 您无法分配到非本地范围.(注意:`al`是*mutable*;这就是为什么这样做的原因.) (3认同)
  • 我认为,为了清楚起见,重要的是区分变量和包含的值.它总是回到我的指针,所以让我这样说; 你不能指出一个新的列表,但你可以改变指向列表的内容.al - > [v1,v2,v3] al不能改变,但v1,v2和v3可以改变.迈克是完全正确的,这使得它变得可变,因为在我们的术语中,al*是*列表而不是指向列表的指针. (2认同)

Gle*_*ard 5

应该注意,这是Python中的语法故障.Python本身(在字节码级别)可以很好地分配给这些变量; 在2.x中根本没有语法表示你想要这样做.它假定如果您在嵌套级别中分配变量,则意味着它是它的本地变量.

这是一个巨大的缺点; 能够分配到闭包是至关重要的.我曾多次与charlieb的黑客一起解决这个问题.

Python 3使用非常笨拙的"非本地"关键字修复了这个问题:

def function1():
    a = 10
    def function2():
        nonlocal a
        print(a)
        a -= 1
        if a>0:
           function2()
    function2()
function1()
Run Code Online (Sandbox Code Playgroud)

这种语法仅在3.x中可用,这是非常差的; 大多数人都陷入2.x,并且必须继续使用黑客来解决这个问题.这非常需要向后移植到2.x.

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