鱼C论坛

 找回密码
 立即注册
查看: 1271|回复: 8

[已解决]全局变量与局部变量问题

[复制链接]
发表于 2018-3-19 20:50:24 | 显示全部楼层 |阅读模式

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

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

x
def scope_test():  
    def do_local():  
        spam = "local spam"  
    def do_nonlocal():  
        nonlocal spam  
        spam = "nonlocal spam"  
    def do_global():  
        global spam  
        spam = "global spam"  
         
    spam = "test spam"  
    do_local()  
    print("After local assignment:", spam)  
    do_nonlocal()  
    print("After nonlocal assignment:", spam)  
    do_global()  
    print("After global assignment:", spam)  
      
scope_test()  
print("In global scope:", spam)
运行结果为:
QQ图片20180319204845.png
请问为什么最后两个输出不是:global spam,个人觉得感觉倒数第二个输出也应该是global spam
最佳答案
2018-3-20 11:20:55
这是我在遇到你这个问题的时候,自己做的笔记和个人想法,不知道能不能给你提供一点看法。

def scope_test():
        def do_local():
                spam = "local spam"      #此函数定义了另外的一个spam字符串变量,并且生命周期只在此函数内。此处的spam和外部函数的spam是两个变量。
        def do_nonlocal():
                nonlocal  spam        #使用外部函数的spam局部变量,即 spam 先赋值 'test spam'再赋值为'nonlocal spam',并且作用在整个外部函数的作用域内。
                spam = "nonlocal spam"
        def do_global():
                global spam     #此处定义全局变量spam,全局变量里没有spam,所以直接就将spam = 'golbal spam'定义为全局变量了。
                spam = "global spam"
        spam = "test spam"   #此处的spam是外部函数的局部变量,并非全局变量。
        do_local()
        print("After local assignmane:", spam)  
        do_nonlocal()
        print("After nonlocal assignment:",spam)
        do_global()
        print("After global assignment:",spam)
### 特别注意的是,这里输出函数的顺序,尤其'nonlocal spam'命令的函数顺序是在第二,所以第一个函数不受影响,而第三个函数是在执行了第二个函数后执行,所以spam已经被nonlocal了,成了'nonlocal spam'。

scope_test()
print("In global scope:",spam)
输出结果是:
After local assignmane: test spam  
#因为直接在内嵌函数内赋值spam只是复制一个在该内嵌函数内使用的spam,不会影响外部函数的spam,所以输出test spam。
After nonlocal assignment: nonlocal spam  
#因为执行了'nonlocal spam'命令,所以scope_test()函数这个作用域内的spam已经重新赋值为nonlocal spam,所以输出nonlocal spam。
After global assignment: nonlocal spam  
#因为第二步执行了nonlocal,所以这个作用域的spam已经是nonlocal spam, 所以这里也输出nonlocal spam。(注:如果把最后二三的函数调用和print内容调换,do_global()的print会输出test spam而不是nonlocal spam。)
In global scope: global spam  
#函数外本来没有spam赋值,所以直接输出spam是报错的,但是执行了以上scope_test函数后,里面的global spam命令就给本来不存在的全局变量spam赋值了,所以现在就可以输出了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-3-19 21:39:06 | 显示全部楼层
  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"  
  12.     do_local()  
  13.     print("After local assignment:", spam)   #do_local()没有作用还是test spam
  14.     do_nonlocal()  
  15.     print("After nonlocal assignment:", spam)  #do_nonlocal()改变父级函数的值,是nonlocal spam
  16.     do_global()  
  17.     print("After global assignment:", spam)  #do_global()改变全局变量,但scope_test()的变量没有改变还是nonlocal spam
  18.       
  19. scope_test()  
  20. print("In global scope:", spam)
复制代码
#do_global()改变全局变量,是global spam
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-3-19 21:39:11 | 显示全部楼层
2018-03-19_213847.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-3-20 00:24:36 | 显示全部楼层
本帖最后由 tifa2018 于 2018-3-20 10:50 编辑

\ 全局变量与局部变量执行步骤图.png

上面是楼主的程序执行步骤图

上面是楼主的程序执行步骤图

从1开始
1--2--2.1--2.2--2.3--2.4--2.5--2.5.1--2.5.2--2.6--2.7--2.7.1--2.7.2--2.8

--2.9--2.9.1--2.9.2--2.10--2.11

就是这么个顺序。

下面具体分析下程序执行的过程

1  将def scope_test():函数体作为一个整体加载到内存中,但不执行

2  调用def scope_test():开始执行

2.1 将def do_local():函数体作为一个整体加载到内存中,但不执行

2.2 将def do_nonlocal(): 函数体作为一个整体加载到内存中,但不执行

2.3 将 def do_global():  函数体作为一个整体加载到内存中,但不执行

2.4 执行 spam = "test spam"

2.5 调用 def do_local():函数

2.5.1  执行 def do_local():函数

2.5.2  执行 spam = "local spam"

--完成2.5.2之后  def do_local():函数结束,其所占的内存被回收, spam =

"local spam"数据被销毁

2.6 执行print("After local assignment:", spam)语句

由于没有global关键字,这里优先读取局部变量,即spam = "test spam"

打印出After local assignment: test spam

2.7  调用do_nonlocal()函数

2.7.1 执行def do_nonlocal():

遇到 nonlocal 声明,nonlocal关键字用来在函数外层(非全局)变量。

这里的外层即为def scope_test():这个作用域内

2.7.2  执行spam = "nonlocal spam"语句

这时def scope_test():这个作用域内由以前的spam = "test spam"被重新覆盖为

spam = "nonlocal spam"


--def do_nonlocal():函数体结束

2.8 执行 print("After nonlocal assignment:", spam)语句

由于spam被重新赋值为"nonlocal spam",这里输出

After nonlocal assignment: nonlocal spam

2.9 调用do_global()函数

2.9.1 执行def do_global(): 函数

2.9.2   执行 spam = "global spam"   语句

遇到global声明,global关键字用来在函数整体作用域使用全局变量。类似于在

def scope_test():上面写了一句spam = "global spam"  


--def do_global(): 函数体结束

2.10 执行print("After global assignment:", spam)语句

由于这一层级作用域没有global关键字,这里优先读取局部变量,即被修改过一次的

spam = "nonlocal spam"

这里输出After global assignment: nonlocal spam

2.11执行print("In global scope:", spam)语句

由于在2.9.2 spam被声明了全局变量,即spam = "global spam"  

所以这里输出

In global scope: global spam
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 2 反对 0

使用道具 举报

 楼主| 发表于 2018-3-20 09:50:16 | 显示全部楼层
tifa2018 发表于 2018-3-20 00:24
\

上面是楼主的程序执行步骤图

谢谢您的耐心细致解答,其中2.7.2最后一句可能是笔误,我觉得应该为:---def do_nonlocal函数体结束。
另外,还有一点不清楚‘’由于这一层级作用域没有global关键字,这里优先读取局部变量,即被修改过一次的‘’,如何分析这一层级的作用域,他的作用域为何没有global关键字。还望您抽空解答,十分感谢!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-3-20 10:49:08 | 显示全部楼层
本帖最后由 tifa2018 于 2018-3-20 10:51 编辑
IT追梦赤子心 发表于 2018-3-20 09:50
谢谢您的耐心细致解答,其中2.7.2最后一句可能是笔误,我觉得应该为:---def do_nonlocal函数体结束。
...


是写错了,改过来了

关于函数的层级
可以看图
函数作用域分析.jpg

函数整体是米色的区域

第一层函数是青色的区域

第二层的3个是粉色的区域

在青色的区域里,没有global关键字,只有执行2.7.2时spam = "test spam"被重新覆盖为

spam = "nonlocal spam",所以后来执行到了2.10这时输出的是spam = "nonlocal spam"
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-3-20 11:20:55 | 显示全部楼层    本楼为最佳答案   
这是我在遇到你这个问题的时候,自己做的笔记和个人想法,不知道能不能给你提供一点看法。

def scope_test():
        def do_local():
                spam = "local spam"      #此函数定义了另外的一个spam字符串变量,并且生命周期只在此函数内。此处的spam和外部函数的spam是两个变量。
        def do_nonlocal():
                nonlocal  spam        #使用外部函数的spam局部变量,即 spam 先赋值 'test spam'再赋值为'nonlocal spam',并且作用在整个外部函数的作用域内。
                spam = "nonlocal spam"
        def do_global():
                global spam     #此处定义全局变量spam,全局变量里没有spam,所以直接就将spam = 'golbal spam'定义为全局变量了。
                spam = "global spam"
        spam = "test spam"   #此处的spam是外部函数的局部变量,并非全局变量。
        do_local()
        print("After local assignmane:", spam)  
        do_nonlocal()
        print("After nonlocal assignment:",spam)
        do_global()
        print("After global assignment:",spam)
### 特别注意的是,这里输出函数的顺序,尤其'nonlocal spam'命令的函数顺序是在第二,所以第一个函数不受影响,而第三个函数是在执行了第二个函数后执行,所以spam已经被nonlocal了,成了'nonlocal spam'。

scope_test()
print("In global scope:",spam)
输出结果是:
After local assignmane: test spam  
#因为直接在内嵌函数内赋值spam只是复制一个在该内嵌函数内使用的spam,不会影响外部函数的spam,所以输出test spam。
After nonlocal assignment: nonlocal spam  
#因为执行了'nonlocal spam'命令,所以scope_test()函数这个作用域内的spam已经重新赋值为nonlocal spam,所以输出nonlocal spam。
After global assignment: nonlocal spam  
#因为第二步执行了nonlocal,所以这个作用域的spam已经是nonlocal spam, 所以这里也输出nonlocal spam。(注:如果把最后二三的函数调用和print内容调换,do_global()的print会输出test spam而不是nonlocal spam。)
In global scope: global spam  
#函数外本来没有spam赋值,所以直接输出spam是报错的,但是执行了以上scope_test函数后,里面的global spam命令就给本来不存在的全局变量spam赋值了,所以现在就可以输出了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-3-20 17:15:26 | 显示全部楼层
老司基 发表于 2018-3-20 11:20
这是我在遇到你这个问题的时候,自己做的笔记和个人想法,不知道能不能给你提供一点看法。

def scope_te ...

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

使用道具 举报

 楼主| 发表于 2018-3-20 17:15:59 | 显示全部楼层
tifa2018 发表于 2018-3-20 10:49
是写错了,改过来了

关于函数的层级

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-24 10:23

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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