Python 3中的nonlocal语句

最近在看Python 3,其中变量作用域增加了一个nonlocal关键字,用来指定非全局、非本地作用域外的封闭作用域中的变量。

nonlocal_stmt ::=  "nonlocal" identifier ("," identifier)*

nonlocal语句会让所列标示符identifier引用之前的最近封闭作用域的绑定变量,除了全局作用域外。 但是nonlocal必须引用之前封闭作用域存在的变量(global则可以声明不存在的)。 而且nonlocal语句所声明的标示符不能与已有的本地变量重名。

例子:

def scope_test():
    def do_local():
        spam = "local spam"
    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"
    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)

输出结果是:

After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

注意局部的赋值 (默认) 并没有改变scope_test绑定的spam. 而nonlocal则改变了scope_test中的spam, 而global则改变了模块级别的绑定。 可以看到在global赋值之前并没有绑定spam的值.

有了nonlocal语句,Python的闭包就不只能只读访问非本地作用域的变量了。

def foo(num):
    count = 0
    def bar():
        nonlocal count
        nonlocal num
        num += 1
        count += 1
        print("num is %d" % num)
        print("bar invoke %d times" % count)
    return bar

func = foo(10)

func()
func()

运行结果:

num is 11
bar invoke 1 times
num is 12
bar invoke 2 times

参考文献:

The nonlocal statement - The Python Language Reference

Python的作用域和命名空间 - Python 3文档(简体中文)

Alvie's Blog

Alvie's Blog

If you're going through hell, keep going

comments powered by Disqus
rss facebook twitter github youtube mail spotify instagram linkedin google pinterest medium