为什么要使用nonlocal

  Python3中加入了新的关键字nonlocal,当在一个嵌套的函数中对变量申明为nonlocal时,就明确表示这个变量是外部函数中定义的变量。也许会有这么一个问题:按照python的LEGB原则,在函数本地作用域找不到变量的情况下,解释器会自动在外层函数寻找,nonlocal关键字岂不是显得多余?   是的,当一个函数在本地作用域找不到变量申明时会向外层函数寻找,这在函数闭包中很常见。如下:

1 def test(num1):
2     def add(num2):
3         return num1 + num2
4     return add
5     
6 a = test(1)
7 b = test(2)
8 print(a(1))
9 print(b(1))

输出为:

2
3

但是在本地作用域中使用的变量后,还想对此变量进行更改赋值就会报错。如下:

def test():
    count = 1
    def add():
        print(count)
        count += 1
    return add

a = test()
a()

输出为:

---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-6-24732f13d2b6> in <module>()
      7 
      8 a = test()
----> 9 a()

<ipython-input-6-24732f13d2b6> in add()
      2     count = 1
      3     def add():
----> 4         print(count)
      5         count += 1
      6     return add

UnboundLocalError: local variable 'count' referenced before assignment

在上面代码中,如果在使用count前面加上关键字nonlocal申明就可解决这个问题:

def add():
    count = 1
    def fun():
        nonlocal count
        print(count)
        count += 1
    return fun

a = add()
a()
a()

输出为:

1
2

  上面代码完美地解决了函数嵌套调用外部变量的问题;另外,如果从另一个角度来看我们给此函数增加了记录函数状态的功能。当然,这也可以通过申明全局变量来实现增加函数状态的功能。当这样会出现以下问题:

  1. 每次调用函数时,都得在全局作用域申明变量。别人调用函数时还得查看函数内部代码。

  2. 当函数在多个地方被调用并且同时记录着很多状态时,会造成非常地混乱。

  使用nonlocal的好处是,在为函数添加状态时不用额外地添加全局变量,因此可以大量地调用此函数并同时记录着多个函数状态,每个函数都是独立、独特的。针对此项功能其实还个一个方法,就是使用类,通过定义__call__可实现在一个实例上直接像函数一样调用。

posted on 2017-03-12 18:22  科幻vs现实  阅读(7999)  评论(0编辑  收藏  举报

导航