嵌套功能更改外部函数中不起作用的变量


def some_func(a): 
    def access_a():
        print(a)
    access_a()

输出a的值。但是,如果我想在嵌套函数中更改a

def some_func(a): 
    def change_a():
        a += 1
        print(a)
    change_a()

它提高了UnboundLocalError异常。

我知道a是一个非局部变量,但是为什么我可以在不声明nonlocal a的情况下访问它?

python范围规则101:

  1. 除非明确声明为global(Python 2.x和3.x)或nonlocal(仅Python 3.x),否则将绑定在功能体中的名称被视为local。无论何时发生分配在功能的身体中,这都是正确的。试图在局部变量绑定之前读取当然是错误的。

  2. 如果读取名称但没有绑定在函数的身体中,则将在封闭示波器(如果有的话)中查找它。NB:函数参数实际上是本地名称,因此永远不会在封闭范围中查找它们。

请注意,a += 1主要是a = a + 1的快捷方式,因此在您的示例中,a是局部的(绑定在函数的身体中,而不是明确声明的全局或非局限性),但是您尝试读取它(a = a+1的RHS的RHS)。

在Python 3中,您可以使用nonlocal语句解决此问题:

>>> def outer(a):
...    def change():
...       nonlocal a
...       a += 1
...    print("before : {}".format(a))
...    change()
...    print ("after : {}".format(a))
... 
>>> outer(42)
before : 42
after : 43

python 2没有nonlocal,因此规范的hack是将变量包裹在可变的容器中(通常是list,但任何可变的对象都可以使用):

>>> def outer(a):
...     _a = [a]
...     def change():
...         _a[0] += 1
...     print("before : {}".format(_a[0]))
...     change()
...     print ("after : {}".format(_a[0]))
... 
>>> outer(42)
before : 42
after : 43

至少可以说这很丑陋。

现在封闭非常方便,它们主要是对象的功能对应物:在保留此状态的封装时在一组函数之间共享状态的一种方法,因此,如果您发现自己需要nonlocal变量适当的类可能是一个更干净的解决方案(尽管可能不是为了您的示例,而不是返回内部功能,而只能在内部使用它)。

我有两个解决方案:

#first one:
# try with list, compound data types dict/list
def some_func(a): 
    def change_a():
        a[0] += 1
        print(a[0])
    change_a()
some_func([1])
>>> 2

#second one
#reference pointer 
from ctypes import *
def some_func_ctypes(a):
    def change_a():
      a[0] += 1
      print a.contents, a[0]
    change_a()
i = c_int(1)
pi = pointer(i)
some_func_ctypes(pi)
>>> c_int(2) 2

使用+=操作员时,将对a的新值分配。这将a变成了口译员眼中的当地人。

最新更新