鱼C论坛

 找回密码
 立即注册
查看: 769|回复: 9

[已解决]global和nonlocal应用上有啥区别?

[复制链接]
发表于 2020-3-31 23:30:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
global和nonlocal应用上有啥区别
最佳答案
2020-3-31 23:57:06
第一,两者的功能不同。global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量,而nonlocal关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal位置会发生错误(最上层的函数使用nonlocal修饰变量必定会报错)。

第二,两者使用的范围不同。global关键字可以用在任何地方,包括最上层函数中和嵌套函数中,即使之前未定义该变量,global修饰后也可以直接使用,而nonlocal关键字只能用于嵌套函数中,并且外层函数中定义了相应的局部变量,否则会发生错误(见第一)。


接下来是得到结论的过程

我们先来看一个代码片段,看看默认情况下输出结果是什么:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



上面的代码片段中没有使用global或nonlocal关键字,是为了看一下默认情况下的输出结果。

可以看到变量x在三次输出中是同一个变量(值相同,地址也相同),都是全局变量,在print函数中使用三个参数是为了方便识别变量,第一个参数是print运行的位置,第二个参数是变量x保存的值,第三个参数是变量x保存的值的地址(这个有待考证)。

如果我们在func函数中修改x的值呢?

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到func函数中x的值和地址都变了,但没有影响函数外边的x的值和地址(main1和main2的数据相同)。所以func函数内的x变量和函数外的x变量是两个变量,而func内的x变量是局部变量,修改它的值不影响全局变量。

第一回合:在函数内部使用了与全局变量同名的变量,如果不对该变量赋值(修改变量),那么该变量就是全局变量,如果对该变量进行赋值,那么该变量就是局部变量。

如果我们想在func函数内修改全局变量x呢?我们先试试用global(全局)。

                               
登录/注册后可看大图



运行后报错,提示语法错误。原来global修饰变量时不能直接赋值,修改为如下:

                               
登录/注册后可看大图



运行结果:

                               
登录/注册后可看大图



可以看到main1位置的x和func内部func1位置的x是同一个值,但和func内部的func2以及main2位置的x不一样了,反而是main2处的x和func内部的x变量是同一个。

第二回合:global关键字修饰函数内部变量后标志其是全局变量(这里不能说global将x从局部变量改为了全局变量),如果用global修饰函数内的变量,必须在使用该变量前进行修饰(否则会发生变量未定义的错误,请你自己尝试一下)

我们试试nonlocal关键字呢?

                               
登录/注册后可看大图



报错了,无法使用nonlocal关键字。

接下来我们看看怎样使用nonlocal关键字。

我们先添加一个嵌套函数:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到嵌套函数内默认使用的也是全局变量。我们在func函数中修改一下x的值试试。

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到在func函数中修改x后,x被标识成局部变量,它的改变并没有影响全局变量x,但嵌套函数ifunc中的x受到了影响,显示ifunc中的x是func函数中的局部变量。

我们再继续修改一下ifunc中x的值。

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到在ifunc修改x的之后即没有影响func中的局部变量x,也没有影响全局变量x,ifunc中的x是函数ifunc自己的局部变量。

第三回合:如果在嵌套函数和函数(这里指包含嵌套函数的那个函数)中存在和全局变量同名的变量,如果直接使用,而不修改变量的值,那么这三个位置的变量使用的是同一个全局变量,如果在函数中修改了变量值,那么该变量会被标识为该函数的局部变量,嵌套函数直接使用时使用的是该函数的局部变量。如果在嵌套函数中修改同名变量的值,那么嵌套函数中的该变量会被标识为该嵌套函数的局部变量,它的修改不影响函数中同名变量和全局变量。

我们在嵌套函数中添加global关键字试试。

先不修改ifunc中x的值:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看出嵌套函数ifunc中的x是全局变量。

再修改一下ifunc中x的值试试:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看出嵌套函数中x是全局变量,但它的修改没有影响到func函数中的同名局部变量。

我们在前边已经发现在func函数中直接使用nonlocal关键字发生了报错,我们再试试在ifunc中使用nonlocal关键字:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到nonlocal修饰后,ifunc中的x和func中的x是同一个变量,ifunc中修改x的值影响了func中的x(因为是一个变量),但并没有影响全局变量x。

再扩展一下:

在func函数中用global修饰x并修改ifunc中x的值,看看有什么变化:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



我们再用nonlocal修饰一下ifunc函数中的x:

                               
登录/注册后可看大图



运行时发生报错,提示没有为ifunc中的x找到绑定。

第四回合:global可以在任何地方修饰变量,而且被global修饰的变量直接被标识为全局变量,对该变量修改会影响全局变量的值,但不影响函数中未被global修饰的同名变量(依然是局部变量),nonlocal只能在嵌套函数(可能还有其他的地方,我还没有检查)中使用,用于标识嵌套函数中的变量是包含该嵌套函数的函数中的同名变量,在嵌套函数中修改变量会影响函数中的变量。如果在函数中使用global修饰了变量,那么在嵌套函数中用nonlocal修饰同名变量会发生报错,因为nonlocal表示该变量在函数中已经定义,但检查时因为同名变量被global修饰为全局变量,所以不存在同名的局部变量,从而导致错误
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-3-31 23:37:18 | 显示全部楼层
本帖最后由 蒋博文 于 2020-4-1 08:03 编辑

看四楼
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-31 23:37:50 | 显示全部楼层
本帖最后由 蒋博文 于 2020-4-1 08:03 编辑

看下面一楼
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-31 23:57:06 | 显示全部楼层    本楼为最佳答案   
第一,两者的功能不同。global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量,而nonlocal关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal位置会发生错误(最上层的函数使用nonlocal修饰变量必定会报错)。

第二,两者使用的范围不同。global关键字可以用在任何地方,包括最上层函数中和嵌套函数中,即使之前未定义该变量,global修饰后也可以直接使用,而nonlocal关键字只能用于嵌套函数中,并且外层函数中定义了相应的局部变量,否则会发生错误(见第一)。


接下来是得到结论的过程

我们先来看一个代码片段,看看默认情况下输出结果是什么:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



上面的代码片段中没有使用global或nonlocal关键字,是为了看一下默认情况下的输出结果。

可以看到变量x在三次输出中是同一个变量(值相同,地址也相同),都是全局变量,在print函数中使用三个参数是为了方便识别变量,第一个参数是print运行的位置,第二个参数是变量x保存的值,第三个参数是变量x保存的值的地址(这个有待考证)。

如果我们在func函数中修改x的值呢?

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到func函数中x的值和地址都变了,但没有影响函数外边的x的值和地址(main1和main2的数据相同)。所以func函数内的x变量和函数外的x变量是两个变量,而func内的x变量是局部变量,修改它的值不影响全局变量。

第一回合:在函数内部使用了与全局变量同名的变量,如果不对该变量赋值(修改变量),那么该变量就是全局变量,如果对该变量进行赋值,那么该变量就是局部变量。

如果我们想在func函数内修改全局变量x呢?我们先试试用global(全局)。

                               
登录/注册后可看大图



运行后报错,提示语法错误。原来global修饰变量时不能直接赋值,修改为如下:

                               
登录/注册后可看大图



运行结果:

                               
登录/注册后可看大图



可以看到main1位置的x和func内部func1位置的x是同一个值,但和func内部的func2以及main2位置的x不一样了,反而是main2处的x和func内部的x变量是同一个。

第二回合:global关键字修饰函数内部变量后标志其是全局变量(这里不能说global将x从局部变量改为了全局变量),如果用global修饰函数内的变量,必须在使用该变量前进行修饰(否则会发生变量未定义的错误,请你自己尝试一下)

我们试试nonlocal关键字呢?

                               
登录/注册后可看大图



报错了,无法使用nonlocal关键字。

接下来我们看看怎样使用nonlocal关键字。

我们先添加一个嵌套函数:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到嵌套函数内默认使用的也是全局变量。我们在func函数中修改一下x的值试试。

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到在func函数中修改x后,x被标识成局部变量,它的改变并没有影响全局变量x,但嵌套函数ifunc中的x受到了影响,显示ifunc中的x是func函数中的局部变量。

我们再继续修改一下ifunc中x的值。

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到在ifunc修改x的之后即没有影响func中的局部变量x,也没有影响全局变量x,ifunc中的x是函数ifunc自己的局部变量。

第三回合:如果在嵌套函数和函数(这里指包含嵌套函数的那个函数)中存在和全局变量同名的变量,如果直接使用,而不修改变量的值,那么这三个位置的变量使用的是同一个全局变量,如果在函数中修改了变量值,那么该变量会被标识为该函数的局部变量,嵌套函数直接使用时使用的是该函数的局部变量。如果在嵌套函数中修改同名变量的值,那么嵌套函数中的该变量会被标识为该嵌套函数的局部变量,它的修改不影响函数中同名变量和全局变量。

我们在嵌套函数中添加global关键字试试。

先不修改ifunc中x的值:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看出嵌套函数ifunc中的x是全局变量。

再修改一下ifunc中x的值试试:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看出嵌套函数中x是全局变量,但它的修改没有影响到func函数中的同名局部变量。

我们在前边已经发现在func函数中直接使用nonlocal关键字发生了报错,我们再试试在ifunc中使用nonlocal关键字:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



可以看到nonlocal修饰后,ifunc中的x和func中的x是同一个变量,ifunc中修改x的值影响了func中的x(因为是一个变量),但并没有影响全局变量x。

再扩展一下:

在func函数中用global修饰x并修改ifunc中x的值,看看有什么变化:

                               
登录/注册后可看大图



输出结果:

                               
登录/注册后可看大图



我们再用nonlocal修饰一下ifunc函数中的x:

                               
登录/注册后可看大图



运行时发生报错,提示没有为ifunc中的x找到绑定。

第四回合:global可以在任何地方修饰变量,而且被global修饰的变量直接被标识为全局变量,对该变量修改会影响全局变量的值,但不影响函数中未被global修饰的同名变量(依然是局部变量),nonlocal只能在嵌套函数(可能还有其他的地方,我还没有检查)中使用,用于标识嵌套函数中的变量是包含该嵌套函数的函数中的同名变量,在嵌套函数中修改变量会影响函数中的变量。如果在函数中使用global修饰了变量,那么在嵌套函数中用nonlocal修饰同名变量会发生报错,因为nonlocal表示该变量在函数中已经定义,但检查时因为同名变量被global修饰为全局变量,所以不存在同名的局部变量,从而导致错误
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-1 08:51:36 | 显示全部楼层
4楼总结的应该非常好。但我这边看到的只有文字,举例中的图片都一直在转圈圈。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-1 08:52:14 | 显示全部楼层
蒋博文 发表于 2020-3-31 23:57
第一,两者的功能不同。global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量, ...

图片出不来呢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-1 09:09:40 | 显示全部楼层

能出来,我这边可以看到
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-1 10:22:41 From FishC Mobile | 显示全部楼层
蒋博文 发表于 2020-3-31 23:57
第一,两者的功能不同。global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量, ...

点击重新加载……
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-1 10:28:15 | 显示全部楼层

鼠标右击看不到的图片,然后又一个重新加载图片的选项,点一下试试。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-1 10:30:57 | 显示全部楼层
蒋博文 发表于 2020-4-1 10:28
鼠标右击看不到的图片,然后又一个重新加载图片的选项,点一下试试。

我这没有
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-27 06:15

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表