python nonlocal 与 global 详解

变量作用域问题

case1

通常在函数之外无法访问到函数内的变量

def f1():
    a=1
print(a)

NameError: name 'a' is not defined

case2

但函数内部的函数,是可以访问到外部函数的变量的。

def f1():
    a=1
    def f2():
    	print(a)
    f2()
f1()

1

case3

但对于int tuple str 等不可变变量,内部变量只能访问不能修改。

def f1():
    a=1
    def f2():
        a+=1
        print(a)
    f2()
f1()

Traceback (most recent call last):
  File "xxx.py", line 11, in <module>
    f1()
  File "xxx.py", line 10, in f1
    f2()
  File "xxx.py", line 8, in f2
    a+=1
UnboundLocalError: local variable 'a' referenced before assignment

这个报错的逻辑大概是 能修改的是一个局部变量a, 你在修改一个变量a,但并没有这个局部变量a, 对于f2来说, 这个a是一个外部变量而不是局部变量。

case4

因此我们可以重新在函数内部中定义一个局部变量a,之后我们的操作都是对这个局部变量的操作了,与外部变量无关。

def f1():
    a = 1
    def f2():
        a = 1
        a += 1
        print('内层函数:', a)
    f2()
    print('外层函数:', a)
f1()

内层函数: 2
外层函数: 1

case5

case3这提到了不可变变量,对应list dic等可变变量来说,其实能改变的也是其内部的值而不是变量本身。可以类比于c++中的常量指针,可以修改指针指向的地址的值。

def f1():
    a = [1]
    def f2():
        a[0] += 1
        print('内层函数:', a[0])
    f2()
    print('外层函数:', a[0])
f1()

内层函数: 2
外层函数: 2

闭包

在case2中,既然f2可以访问到f1的内部变量,那么如果将f2作为f1的返回值,自然就可以通过f2在外部访问到f1的内部变量。

def f1():
    a=1
    def f2():
        return a
    return f2
f2=f1()
print(f2())

1

这个f2就是闭包。具体可以参考下面这篇文章,本篇不展开讨论。

Python闭包(Closure)详解 - 知乎 (zhihu.com)

nonlocal

python nonlocal深度理解_大义Python的博客-CSDN博客_python銝要onlocal

针对case3,如果我们就是想在内部函数中修改变量a,可以借助nonlocal关键字。

nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量。可以理解为,使用nonlocal关键字,内层可以将外层变量看做本地变量,赋予了内层函数对外层函数变量的修改权。

case6

def f1():
    a=1
    def f2():
        nonlocal a
        a+=1
        print('内层函数:', a)
    f2()
    print('外层函数:', a)
f1()

内层函数: 2
外层函数: 2

case7

因此必须外部有这个变量才能使用此关键字。

def f1():
    # a=1
    def f2():
        nonlocal a
        a+=1
        print('内层函数:', a)
    f2()
    print('外层函数:', a)
f1()

    nonlocal a
    ^
SyntaxError: no binding for nonlocal 'a' found

global

global 的作用是将变量声明为全局变量,即内部变量允许外部访问

case8

def f1():
    a = 1
    def f2():
        global a
        a=1
        a += 1
        print('内层函数:', a)
    f2()
    print('外层函数:', a)
f1()
print('外部:',a)

内层函数: 2
外层函数: 1
外部: 2

case9

def f1():
    # a = 1
    def f2():
        global a
        a=1
        a += 1
        print('内层函数:', a)
    f2()
    print('外层函数:', a)
f1()
print('外部:',a)

内层函数: 2
外层函数: 2
外部: 2

对比case8和case9,在7中,由于外层函数声明了变量a,因此会优先使用局部变量。而在case8中,全部都是使用的内层函数中声明的全局变量。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值