python global和nonlocal_Python中的global和nonlocal关键字

在进入正题之前先简单说明一下:局部变量:函数或者方法里面定义的变量;

全局变量:本文指module级别的变量(一个python文件就是一个module)。

global

先看个例子:a = 1

def func1():

print("func1:", a)

def func2():

a = 10

print("func2:", a)

def func3():

print("func3:", a)

a = 100

print("func3:", a)

if __name__ == "__main__":

print(a)

func1()

func2()

print(a)

func3()

输出结果如下:1

func1: 1

func2: 10

1

Traceback (most recent call last):

File "/Users/allan/Desktop/test/test/test.py", line 24, in

func3()

File "/Users/allan/Desktop/test/test/test.py", line 11, in func3

print("func3:", a)

UnboundLocalError: local variable 'a' referenced before assignment

func1和func2的输出应该没有什么疑问,就是局部变量和全局变量作用域的问题:模块内都可以访问到全局变量;函数内局部变量与全局变量重名,会将全局变量隐藏掉(这种最好的理解方式就是把局部变量换个名字)。这里不再赘述。func3中,因为定义了和全局变量同名的a,所以,全局变量在整个方法中都被隐藏掉了,这个与局部变量a定义的位置没有关系。所以,在局部变量a定义之前使用a就会报异常。

这里需要说明的一个关键点是:函数或方法中的任何地方,当给某个变量赋值的时候(特别要注意这个场景限定,后面会有一个例子),Python会将该变量当成一个局部变量,除非显式的使用global关键字声明该变量为全局变量。当然,赋值是写的过程,如果是读的话,会先查有没有这个名字的局部变量,如果没有,再查有没有这个名字的全局变量。

所以说,一般global的使用场景就是当我们想在函数里面修改全局变量的值。看下面代码:a = 1

def func4():

global a

a = 100

print("func4:", a)

if __name__ == "__main__":

print(a)

func4()

print(a)

输出如下:1

func4: 100

100

借助于global关键字,我们成功的在函数func4里面修改了全局变量a的值。func4和之前的func2的唯一区别就在于没有使用global关键字。

所以,这样来看,其实global的使用还是挺简单的。下面看另外一个和global作用非常像的关键字nonlocal。

nonlocal

nonlocal关键字是Python3引入的(见PEP 3104 - Access to Names in Outer Scopes, The specification for the nonlocal statement.),PEP里面对该关键字的作用已经有了大概的说明了:访问作用域之外的(对象)名字。

还是先看个例子:def outside():

msg = 'outside'

def inside():

msg = 'inside'

print(msg)

inside()

print(msg)

if __name__ == "__main__":

outside()

这个例子和之前的例子实质一样,inside里面的msg变量其实是inside函数创建的一个局部变量而已,只不过和外层的msg同名了而已,但实质还是两个完全不同的变量。所以输出也并不意外:inside

outside

现在问题来了,如果我想在inside里面给外层的msg重新赋值(即修改外层的msg)怎么办?使用刚才介绍的global关键字行不行?试一下便知:def outside():

msg = 'outside'

def inside():

global msg

msg = 'inside'

print(msg)

inside()

print(msg)

if __name__ == "__main__":

outside()

输出结果:inside

outside

Oh, holy shit,没有成功。其实也正常,因为外层的msg并不是一个全局变量,它的作用域并不是module级别的,而只是outside函数范围内的而已。现在能实现我们上面那个需求的方式就是用nonlocal代替上面代码中的global:def outside():

msg = 'outside'

def inside():

nonlocal msg

msg = 'inside'

print(msg)

inside()

print(msg)

if __name__ == "__main__":

outside()

输出如下:inside

inside

所以,nonlocal这个关键字主要就是在闭包函数(enclosing function or closures)中使用,可以修改外层函数里面的对象。

综合来看nonlocal和global的确是非常像的,不同之处在于前者用于修改函数作用域内的局部变量,而后者用于修改module级别的全局变量。

提提神

文章最后,再来一个提神的,看下面代码输出什么:def outside():

msg = {"outside": 1}

def inside():

msg['inside'] = 2

print(msg)

inside()

print(msg)

if __name__ == "__main__":

outside()

输出结果如下:{'outside': 1, 'inside': 2}

{'outside': 1, 'inside': 2}

Oh, holy shit,有没有意外?这里没有使用nonlocal修改msg,但里面的inside函数还是修改了外边的msg。不是说不行吗?

nonlocal:这个锅我不背。

其实这个的确和nonlocal没有什么关系,文章前面已经提醒过了,只有在给变量赋值这个场景下,且没有使用global和nonlocal,Python才去创建本函数的局部变量,而不是访问全局或外层函数的变量。而上面的msg['inside'] = 2其实不是个变量赋值语句。

What?没错,字典的插入的确不是变量赋值,而是方法调用(调用的是__setitem__方法)。所以,msg['inside'] = 2的底层其实是执行了如下语句:msg.__setitem__("inside", 2)

有没有很提神?(〃'▽'〃)

References:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言用于封装代码的单元,可以实现代码的复用和模块化。C语言定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言用于存储同类型数据的结构,可以通过索引访问和修改数组的元素。字符串是C语言用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值