鱼C论坛

 找回密码
 立即注册
查看: 2285|回复: 4

[已解决]python3.6 官方文档上nonlocal和global 一个例子的疑问

[复制链接]
发表于 2018-9-22 16:55:49 | 显示全部楼层 |阅读模式
17鱼币
源代码:
  1. def scope_test():
  2.     def do_local():
  3.         spam = "local spam"

  4.     def do_nonlocal():
  5.         nonlocal spam
  6.         spam = "nonlocal spam"

  7.     def do_global():
  8.         global spam
  9.         spam = "global spam"

  10.     spam = "test spam"
  11.     do_local()
  12.     print("After local assignment:", spam)
  13.     do_nonlocal()
  14.     print("After nonlocal assignment:", spam)
  15.     do_global()
  16.     print("After global assignment:", spam)

  17. scope_test()
  18. print("In global scope:", spam)
复制代码


输出的结果为:
  1. After local assignment: test spam
  2. After nonlocal assignment: nonlocal spam
  3. After global assignment: nonlocal spam
  4. In global scope: global spam
复制代码


疑问:
  1. def scope_test():
  2.     def do_local():
  3.         spam = "local spam"

  4.     def do_nonlocal():
  5.         nonlocal spam
  6.         spam = "nonlocal spam"

  7.     def do_global():
  8.         global spam
  9.         spam = "global spam"

  10.     spam = "test spam"
  11.    
  12.     """
  13.     疑问1:do_local并没有引用全局变量,为什么打印出来的是全局变量spam?即"test spam"
  14.     这个函数不是该直接打印"local spam"吗?
  15.     """
  16.    
  17.     do_local()
  18.     print("After local assignment:", spam)
  19.    
  20.     """疑问2:我对do_nonlocal函数的理解是:用nonlocal导入了上一层的spam变量
  21.         也就是do_local函数中的spam变量的值,然后该函数把这个spam重新赋值为"nonlocal spam"
  22.         也就是说,执行了这个函数后,do_local函数中的spam也改变了。不知道是否理解正确"""
  23.    
  24.     do_nonlocal()
  25.     print("After nonlocal assignment:", spam)
  26.     """
  27.     疑问3:对do_global的理解:通过global引入全局变量,即"test spam",并将全局变量的spam
  28.     重新赋值为"global spam",那么为什么最后打印出来的是"nonlocal spam"?
  29.     """
  30.     do_global()
  31.     print("After global assignment:", spam)

  32. scope_test()
  33. """最后一次打印的spam值为:global spam
  34.     我认为是因为执行了do_nonlocal函数后被重新赋值了。
  35.     所以我就最后一个spam稍微看懂了,其余就没明白,不知道各位大大有没有什么可以帮助我理解的?
  36. """
  37. print("In global scope:", spam)
复制代码
最佳答案
2018-9-22 16:55:50
我把代码改成了这样,让你好理解
  1. def scope_test():
  2.     def do_local():
  3.         spam = "local spam"

  4.     def do_nonlocal():
  5.         nonlocal spam
  6.         spam = "nonlocal spam"

  7.     def do_global():
  8.         global spam
  9.         spam = "global spam"

  10.     spam = "test spam"
  11.     print(id(spam))
  12.     do_local()
  13.     print("After local assignment:", id(spam))
  14.     do_nonlocal()
  15.     print("After nonlocal assignment:", id(spam))
  16.     do_global()
  17.     print("After global assignment:", id(spam))

  18. scope_test()
  19. print("In global scope:", id(spam))
复制代码

输出结果为
  1. 2740280630256
  2. After local assignment: 2740280630256
  3. After nonlocal assignment: 2740280630128
  4. After global assignment: 2740280630128
  5. In global scope: 2740280630000
复制代码

这样就好理解了,第一个spam 赋值是在函数 scope_test下的 是这个函数的局部变量
第一个函数是在自身函数下面建了一个spam局部变量,所以不会被打印
第二个函数是在自身函数下面建了一个可以在scope_test 和  non_local  函数里面使用的局部变量spam
第三个函数是在scope_test外面建立了一个全局变量spam
在do_global 函数执行后,spam并非直接在当前的函数里面创建的spam变量,而是在全局变量中又创建了一个变量
所以这个spam 和 函数中存在的几个spam都不一样
如果,而函数调用属性是这样的,先在函数自身的命名空间找变量名,如果有打印该变量值,然后在上一层命名空间中找如果有变量名,打印变量值,如果没有且在全局变量命名空间,报错
现在你知道do_global为什么返回的为“nonlocal spam”吧,因为在当前的函数命名空间下,已经有了一个叫spam的nonlocal变量名,就不会再去上一层空间找了

最佳答案

查看完整内容

我把代码改成了这样,让你好理解 输出结果为 这样就好理解了,第一个spam 赋值是在函数 scope_test下的 是这个函数的局部变量 第一个函数是在自身函数下面建了一个spam局部变量,所以不会被打印 第二个函数是在自身函数下面建了一个可以在scope_test 和 non_local 函数里面使用的局部变量spam 第三个函数是在scope_test外面建立了一个全局变量spam 在do_global 函数执行后,spam并非直接在当前的函数里面创建的spam变 ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-9-22 16:55:50 | 显示全部楼层    本楼为最佳答案   
我把代码改成了这样,让你好理解
  1. def scope_test():
  2.     def do_local():
  3.         spam = "local spam"

  4.     def do_nonlocal():
  5.         nonlocal spam
  6.         spam = "nonlocal spam"

  7.     def do_global():
  8.         global spam
  9.         spam = "global spam"

  10.     spam = "test spam"
  11.     print(id(spam))
  12.     do_local()
  13.     print("After local assignment:", id(spam))
  14.     do_nonlocal()
  15.     print("After nonlocal assignment:", id(spam))
  16.     do_global()
  17.     print("After global assignment:", id(spam))

  18. scope_test()
  19. print("In global scope:", id(spam))
复制代码

输出结果为
  1. 2740280630256
  2. After local assignment: 2740280630256
  3. After nonlocal assignment: 2740280630128
  4. After global assignment: 2740280630128
  5. In global scope: 2740280630000
复制代码

这样就好理解了,第一个spam 赋值是在函数 scope_test下的 是这个函数的局部变量
第一个函数是在自身函数下面建了一个spam局部变量,所以不会被打印
第二个函数是在自身函数下面建了一个可以在scope_test 和  non_local  函数里面使用的局部变量spam
第三个函数是在scope_test外面建立了一个全局变量spam
在do_global 函数执行后,spam并非直接在当前的函数里面创建的spam变量,而是在全局变量中又创建了一个变量
所以这个spam 和 函数中存在的几个spam都不一样
如果,而函数调用属性是这样的,先在函数自身的命名空间找变量名,如果有打印该变量值,然后在上一层命名空间中找如果有变量名,打印变量值,如果没有且在全局变量命名空间,报错
现在你知道do_global为什么返回的为“nonlocal spam”吧,因为在当前的函数命名空间下,已经有了一个叫spam的nonlocal变量名,就不会再去上一层空间找了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-9-22 17:12:55 | 显示全部楼层
  1. def scope_test():
  2.     def do_local():
  3.         spam = "local spam"

  4.     def do_nonlocal():
  5.         nonlocal spam
  6.         spam = "nonlocal spam"

  7.     def do_global():
  8.         global spam
  9.         spam = "global spam"

  10.     ## 上面只是定义,不会执行,所以不会更改任何东西

  11.     spam = "test spam"    ##现在才定义 spam
  12.     do_local()                  ##调用函数。此函数的 spam 不是以参数的形式传入的,所以会去修改已经被定义的
  13.     print("After local assignment:", spam)
  14.     do_nonlocal()            ## 把局部变量转成 nonlocal,并且重新赋值
  15.     print("After nonlocal assignment:", spam)
  16.     do_global()               ##把nonlocal 变量转成 global,并且重新赋值
  17.     print("After global assignment:", spam)

  18. scope_test()    ##真正调用函数,才会执行上面的指令
  19. print("In global scope:", spam)
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-9-24 17:04:02 | 显示全部楼层
  1. def do_global():
  2.         global spam
  3.         spam = "global spam"
复制代码


do_global为什么返回的为“nonlocal spam”?
执行了该函数后,spam不是会被赋值为"global spam"么,不是应该返回这个?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-9-25 12:12:51 | 显示全部楼层
本帖最后由 claws0n 于 2018-9-25 12:14 编辑
类十三 发表于 2018-9-24 17:04
do_global为什么返回的为“nonlocal spam”?
执行了该函数后,spam不是会被赋值为"global spam"么, ...


嗯,楼上大致描述了。
先讲这个概念 >>  global(    local(    nonlocal    )    )
global 全局变量拥有最大的访问范围,可以透过 local 等访问,不能修改,修改的话要另外修饰。
加了 global 修饰之后,修改的是全局变量。如果没有该变量,则创建一个。应该说是覆盖吧。
  1. c = 10

  2. def f():
  3.     c += 2    ## 这样会报错,因为没有初始值
  4.     print(c)    ## 如果只有这句,会打印 10,访问了全局变量

  5. f()
复制代码

你也许听过【堆栈】这个的东西,了解就好。函数被调用的时候,内存会跳转到另一个地方,从主函数切换到被调用的函数。函数被调用完后,又切换回来,所以局部变量会“消失”,就是这个原因。
现在的问题是,这个全局变量是定义在一个函数里的函数,所以,子函数结束后,变量会随着消失。那在子函数里定义的全局变量又要如何保存?方法就是放到另一个地方暂存,直到程序回到主函数的时候,才放回来。因此,出了 do_global() 之后,global spam 的记忆将在 scope_test() 里消失了。
  1. def do_global():
  2.     global spam
  3.     spam = "global spam"
  4.     print("inside do_global", spam) ## 打印 "inside do_global global spam"
复制代码

那 nonlocal 为什么不会消失呢?同样的操作模式,但nonlocal 是局部变量里的全局变量,在局部范围里,它为王。它的被访问域是 local,但它的记忆如同 global,直到程序结束后才释放,但它又不是 global,所以叫 nonlocal。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-3-29 04:09

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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