Python关键字:global和nonlocal

2018-05-21  本文已影响8人  平仄_pingze

结论

global和nonlocal在局部声明变量,表明变量的定义不在块内,而在全局/上级局部作用域内。

global

先谈一下Python的引用查找循序:
先在当前局部作用域找声明,如果找不到,到上层(包括全局)找

举一个例子:

a = 1
def foo():
    b = a
    return b

print(foo())

程序输出 1。foo()内部没有定义1,它向上层找到了全局变量a。

稍微修改:

a = 1
def foo():
    b = a
    a = 2 # newline
    return b

print(foo())

程序报错:UnboundLocalError: local variable 'a' referenced before assignment
因为这次a在foo()内部声明了,但使用先于声明,是错误的。

再改一下:

a = 1
def foo():
    global a # newline
    b = a
    a = 2
    return b

print(foo())

正常输出1。global关键字声明,foo()中的a即是全局变量a,后面的都是赋值语句。

nonlocal

nonlocal的功能和global类似,只是nonlocal声明的变量在上级局部作用域内,而不是全局定义。
上面的代码中,将global改为nonlocal:

a = 1
def foo():
    nonlocal a
    b = a
    a = 1
    return b
print(foo())

报错:SyntaxError: no binding for nonlocal 'a' found。表明nonlocal不能声明全局变量。

将foo包裹在上层局部作用域中:

def foo_upper():
    a = 1
    def foo():
        nonlocal a
        b = a
        a = 1
        return b
    print(foo())

foo_upper()

正常输出1

nonlocal应用:闭包

利用nonlocal可以实现Python的闭包。
比如:

def adder():
    num = 0
    def add():
        nonlocal num
        num += 1
        return num
    return add

add = adder()
print(add())
print(add())
print(add())
print(add())

打印出了:1 2 3 4

或者,实现一个单例函数(不能同时执行多次)装饰器:

def singlecase(fn):
    '装饰器:单例模式'
    running = False
    @functools.wraps(fn)
    def wrapper(*args, **kargs):
        nonlocal running
        if running:
            raise Exception('单例函数 ' + fn.__name__ + ' 已经在执行')
        running = True
        try:
            return fn(*args, **kargs)
        finally:
            running = False
    return wrapper
上一篇 下一篇

猜你喜欢

热点阅读