Discuss / Python / nonlocal - 用于操作外层作用域中的对象。

nonlocal - 用于操作外层作用域中的对象。

Topic source

Nathan_Hu_

#1 Created at ... [Delete] [Delete and Lock User]
def createCounter():
    n = 0

    def counter():
        nonlocal n
        n += 1
        return n

    return counter

nonlocal

在 Python 中,内层函数对外层作用域中的变量仅有只读访问权限!

而 nonlocal 可以使我们自由地操作外层作用域中的变量!

# 1. 内层函数"可以使用"外层作用域中的变量
def outside():
    msg = 'outside'
    def inside():
        print(msg)
    inside()
    print(msg)

>>> outside()
outside
outside

# 2. 内层函数"无法修改"外层变量
def outside():
    msg = 'outside'
    def inside():
        # 无法操作外层变量,这里实际上新建了一个内层局部变量罢了~
        msg = 'inside'
        print(msg)
    inside()
    print(msg)

>>> outside()
inside
outside

# 3. 使用 nonlocal 修改外层变量
def outside():
    msg = 'outside!'
    def inside():
        nonlocal msg
        msg = 'inside!'
        print(msg)
    inside()
    print(msg)

>>> outside()
inside
inside

感谢普及!!

请教一下如下代码中: def createCounter(): fs = [0] def counter(): fs[0] = fs[0] + 1 return fs[0] return counter 为什么这里内部函数一样使用了外部函数的变量列表fs,却没有报错。

@是我_也不是我 我猜是因为fs[0]=fs[0]+1 是修改列表中的第一个值,并没有重新给fs 赋值,fs不会被当做新的局部变量来初始化。 如果改成 fs=[fs[0]+1] 就会报错。

def createCounter(): fs = [0] def counter(): fs=[fs[0]+1] return fs[0] return counter

@撞一天和尚-当一天钟 恩,我也是这么想的。

廖雪峰

#6 Created at ... [Delete] [Delete and Lock User]

Python有个奇怪的特性:

def outer():
    x = 1
    def inner():
        y = x + 1
        print('y=', y) # y=2
    inner()
    print('x=', x) # x=1

如果inner()引用了x,但没有对x赋值,那么x就会自动查找外层作用域,即x的值为1

但是,如果inner()中有对x的赋值语句:

def outer():
    x = 1
    def inner():
        x = 2
        print('inner x:', x) # 2
    inner()
    print('outer x:', x) # 1

Python解释器会把x解释为inner()的局部变量,也就是outer的x和inner的x互不影响

但是!

如果在inner()中加上y=x+1:

def outer():
    x = 1
    def inner():
        y = x + 1 # UnboundLocalError: local variable 'x' referenced before assignment
        x = 2
        print('inner x:', x) # 2
    inner()
    print('outer x:', x) # 1

会报错UnboundLocalError,因为Python解释器把inner()的x解释为inner()的局部变量,但是x还没有被赋值,无法计算x+1

这个时候唯一的方法是用nonlocal x告诉解释器,inner()引用的x不是新的局部变量,而是outer的x:

def outer():
    x = 1
    def inner():
        nonlocal x
        y = x + 1
        x = 2
        print('inner x:', x) # 2
    inner()
    print('outer x:', x) # 2

所以通常情况下不要在内部函数中对外部作用域的变量重新赋值。

廖雪峰

#7 Created at ... [Delete] [Delete and Lock User]

通常情况下不应该在内部函数中修改外层作用域的值,所以很少会用到nonlocal

实在想修改怎么办?最好是返回一个新的值,然后让外层自己改:

def outer():
    x = 1
    def inner():
        return x + 1
    x = inner()
    print(x) # 2

n = 0 def createCounter(): def counter(): global n n += 1 return n return counter

应该这样子写

Ktine_Xu

#9 Created at ... [Delete] [Delete and Lock User]

nonlocal 是python3以上才支持的关键词,这个教程是采用2.7版本的,你这个弄了半天才知道为什么在我的2.7上面不支持这个关键词

@廖雪峰 廖老师,希望您能够把此留言的#6楼和#7楼补充的内容更新到当前“返回函数”的章节中,或者置顶到此评论区之上;这样如果久了忘了,再回来再翻翻也容易找到。谢谢廖老师


  • 1

Reply