这篇文章写的很赞, 条理清晰, 分析循序渐进, 感谢原作者!
结论:
第一, 两者的功能不同. 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 修饰为全局变量, 所以不存在同名的局部变量, 从而导致错误.
来源: http://www.bubuko.com/infodetail-2997349.html