Python 为什么引入这两个关键词

啥是 global 和 nonlocal

Python 支持的关键词里,global 和 nonlocal 初学者接触的少,不知道是做什么用的;一些人虽然知道它们的作用,但对为什么要引入这两个关键词则有些不知其所以然。

粗浅地说,global 和 nonlocal 是为了在函数中修改全局和闭包变量而引入的关键字。

本文用代码一点点分析引入 global 和 nonlocal 的原因。

一个奇怪的现象

下面,让我们做一个测试。

g =1def fun(): g = 2 return g print(fun(),g)

一般地,我们认为结果应该为 2,2。这一点学过其他语言如 Java、c 的同学尤其认同。

但让我们跑起来,可以看到结果为 2,1。也就是说,函数没有改变全局变量 g

这很奇怪,究其原因是因为:

·Python 认为所有 = 赋值都是在当前作用域新建变量。· 当我们在程序中 g = 1 时,表示当前全局作用域建立 g,赋值 1。· 当我们在函数中 g = 2 时,表示当前局部作用域建立 g,赋值 2。

使用 dis.dis(fun) 分析 fun 函数源代码:

 16           0 LOAD_CONST               1 (2)              2 STORE_FAST               0 (g) 17           4 LOAD_FAST                0 (g)              6 RETURN_VALUE

可见,第 2 条指令 STORE_FAST,这是存储到局部变量的命令。

所以,函数中实际操作的是局部变量。

还有更甚的例子如下,大家猜测下执行结果。

g =1def fun(): g += 1 return gprint(fun(),g)

根据上文,我们知道函数不会改变全局变量 g,那么结果应该是 2,1,这次总算对了吧?

很抱歉,当执行到 g += 1 时,系统报错:UnboundLocalError: local variable 'g' referenced before assignment

仔细观察错误,local variable 'g',这里的 g 仍然被视为局部变量:没有定义(=赋值),就直接 inplace add,当然要报错。

也就是说,所有在局部作用域中对全局变量的赋值、原位赋值都会失败。唯有如下函数给我们带来一丝安慰。

g =1def fun():    return gprint(fun(),g) 

结果 1,1,总算还有个正常的:在局部作用域中引用全局作用域变量正常。

那当我必须修改全局变量时,该怎么办呢?

global 的引入和分析

这就是 global 引入的理由了,将全局变量扩展到函数中来,使函数可以修改全局变量。

g =1def fun(): global g g = 2 return gprint(fun(),g)

结果为 2,2,函数修改了全局变量。我们来看 dis.dis(fun) 的反汇编代码。

 37           0 LOAD_CONST               1 (2)              2 STORE_GLOBAL             0 (g) 38           4 LOAD_GLOBAL              0 (g)              6 RETURN_VALUE

第 2 条指令,STORE_GLOBAL 是将常量 2 赋值给全局变量 g,异于上例中的 STORE_FAST指令对局部变量操作。

故此,我们得出结论:当在函数中读取全局变量时,可以直接使用。但如果需要修改全局变量值,则需要在变量前加上 global 来修饰。

nonlocal 的引入

同样地,当我们书写嵌套函数,需要对闭包中的变量进行修改操作时,我们也需要引入 nonlocal 关键字。

如下函数中,我们定义了闭包,闭包中的变量 e,试图在内嵌函数中进行修改,但没有使用 nonlocal 关键字声明 e。

def outer(): e = 1 def inner(): e = 2 return e return inner

参照上例,我们知道这种修改是徒劳的——因为看反汇编代码 dis.dis(outer()) 可知:

 63           0 LOAD_CONST               1 (2)              2 STORE_FAST               0 (e) 64           4 LOAD_FAST                0 (e)              6 RETURN_VALUE

第 2 条指令 STORE_FAST,操作局部变量,也就是说 inner 里的 e,仍然被视为局部变量。

雷同于上例的 global,这里使用 nonlocal 来在内嵌函数 inner 中修改闭包变量 e。

def outer(): e = 1 def inner(): nonlocal e e = 2 return e return inner

查看此时的反汇编代码 dis.dis(outer()) 可知:

 78           0 LOAD_CONST               1 (2)              2 STORE_DEREF              0 (e) 79           4 LOAD_DEREF               0 (e)              6 RETURN_VALUE

第 2 条指令 STORE_DEREF,操作的是闭包变量,也就是说 inner 里的 e,是可以修改的闭包中的 e。

总结

本文通过分析函数对全局变量和闭包变量的读、写操作,借助于反汇编字节码分析,认清了 global 和 nonlocal 关键字的用法,对其引入和作用有了较为深刻认识。

作者:巩庆奎,大奎,对计算机、电子信息工程感兴趣。gongqingkui at 126.com

(0)

相关推荐

  • 第22天:Python NameSpace & Scope

    命名空间定义了在某个作用域内变量名和绑定值之间的对应关系,命名空间是键值对的集合,变量名与值是一一对应关系.作用域定义了命名空间中的变量能够在多大范围内起作用. 命名空间在python解释器中是以字典 ...

  • 全菊变量和菊部变量

    王菊这波热点来得莫名其妙啊,让我们这些"菊外人"一脸懵逼. 前阵子还自我吐槽了下文章的选题,热点没营养,干货没人看.这下好了,找到了热点与干货的完美结合 是谁的小眼睛,还没看Cro ...

  • 40年前才引入,两广地区大面积养殖,却市场口碑坍塌成“垃圾鱼”

    导读:40年前才引入,两广地区大面积养殖,却市场口碑坍塌成"垃圾鱼" 我国的鱼类资源是相当丰富的,不仅有"青.草.鲢.鳙"这四大常见的家鱼,还有众多的小杂鱼,另 ...

  • excel筛选两个关键词-筛选的高级用法

    excel筛选,可以快速的在一列中查找您需要的内容,这里有两个问题,1.同时查找两个关键词怎么操作?2.查找含有两个关键词的数据怎么操作.这是两个不相干的问题,鉴于本文的标题有些模糊,所以出现了两个问 ...

  • Python实现屏幕截图的两种方式

    使用windows API 使用PIL中的ImageGrab模块 下面对两者的特点和用法进行详细解释. 一.Python调用windows API实现屏幕截图 好处是 灵活 速度快 缺点是: 写法繁琐 ...

  • 解码保险普惠 微保的两大关键词

    订阅 十字财经 掌握独家资讯 8月9日,微保交出了上线9个月以来的第一张成绩单. 其披露情况显示,去年11月上线以来,健康险方面,微医保医疗险已处理了理赔结案5000例,其中79%理赔为24小时赔付到 ...

  • 我们学美食搞餐饮,如何找到正确方法?老祖宗留给我们两个关键词

    最近陆续给大家分享了一些,关于制作和鉴别配方的心得,有实践经验,有理论知识,都是一些个人所见,也经常有共同爱好的朋友,和我进行探讨. 这个过程中,有着各种各种各样的故事,各种各样的感受,体现出了大家不 ...

  • 王阳明心学精髓:一句话,两个关键词!

    阳明先生言工夫,要在'事上磨',而主于'诚意',亦曰'谨独',亦曰'立志',其实皆求能'诚意'耳.诚意之极,即是'知行合一'.'致良知'则即是'诚意'也. 这段话的意思是说,要成就心学工夫,'事上磨' ...

  • 数字化营销的两个关键词:鸡尾酒式渠道组合,乐高式用户关系共创

    -01- 鸡尾酒式渠道组合 如果要把数字化手段来当成武器的话,决策者一定要分清楚两件事,我们是要进攻,还是驻守. 是战争初期,做关键点突破,还是战争后期,清扫战场,维护秩序? 都说让听见炮火的人做决策 ...

  • 腾讯财报超预期投行"买入",我却看到这两个关键词

    腾讯过去二十年,是经历中国互联网产业大发展的二十年,腾讯也是这二十年中最成功的企业之一.今天,整个产业.社会都因为互联网的影响而发生了更加深远的变化,腾讯在这个时候提出组织架构调整,向产业互联网出发, ...

  • 社交和娱乐:看懂陌陌的两个关键词

    来源:懂懂笔记 "我们一路奋斗,不是为了改变世界,而是为了不让世界改变我们." 这是那部著名电影<熔炉>中一句经典的台词.在这个纷乱的时代,改变很容易,坚持自己才是最难 ...