作用域
“作用域”定义了Python在哪一个层次上查找某个“变量名”对应的对象。接下来的问题就是:“Python在查找‘名称-对象’映射时,是按照什么顺序对命名空间的不同层次进行查找的?”
答案就是:使用的是LEGB规则,表示的是Local -> Enclosed -> Global -> Built-in,其中的箭头方向表示的是搜索顺序。
1 | L: 先在局部变量中找,如果找不到 |
其中
1 | Local 可能是在一个函数或者类方法内部。 |
python作用域是以函数、类、模块来区分的,而不是块
也就是说if、while,for并不会影响变量的作用域!!!,python中没有块作用域。
这就能解释python的if name==’mian‘中声明的变量同样是全局变量
练习01
1 | a_var = 'global value' |
结果:
1 | outer before: local value |
分析:
练习02
1 | a = 'global' |
结果:
1 | a is local variable |
可自行分析试试
注意点
01:在函数作用域内修改全局变量通常是个坏主意,因为这经常造成混乱或者很难调试的奇怪错误。如果你想要通过一个函数来修改一个全局变量,建议把它作为一个变量传入,然后重新指定返回值。
02:如果我们提前在全局命名空间中明确定义了for循环变量,也是同样的结果!在这种情况下,它会重新绑定已有的变量:
For循环变量“泄漏”到全局命名空间
1 | b = 1 |
在Python 3.x中,我们可以使用闭包来防止for循环变量进入全局命名空间。下面是一个例子(在Python 3.4中执行):
1 | i = 1 |
为何for里面会有如此奇怪的规则?闭包本身具有独立作用域,所以这里的i对父域不会形成干扰。
还有另一个副作用就是
1 | for i in range(5): |
结果:
1 | 0 |
而不是直观理解的执行一次就退出
代码;
1 | for i in range(5): |
结果:
1 | 5 |
第一:成功污染外面的i
第二:内部i+5只进行了1次,说明i=i+5,右侧的i,是真正的for里面的i,左侧的i是外部的i,但是却未报错unbounderror的错误!(内部的i有赋值,所以理论上外部的i应该是被屏蔽的,应该报错unbound才对,但是没报。即使勉强接受这一点,最终外面的i=9而非4,也很奇怪)
原因:for循环不会引入新的作用域,所以,循环结束后,继续执行print(i),可以正常输出i,原理上与情况3中的if相似。这一点Python就比较坑了,因此写代码时切忌for循环名字要与其他名字不重名才行。
上式中,for里面i+5,到外面的for那里又重新赋值为原有的i(无视了内部对i的修改),所以每次都+5了,而最终结果依然+5,是由于最后一次的i并未被成功赋值,所以最终结果看起来比较奇.
1 | list_1 = [i for i in range(5)] |
情况3中说到过,for循环不会引入新的作用域,那么为什么输出报错呢?真相只有一个:列表生成式会引入新的作用域,for循环是在Local作用域里面的。事实上,lambda、生成器表达式、列表解析式也是函数,都会引入新作用域。
参考
Python中的LEGB规则:https://www.cnblogs.com/GuoYaxiang/p/6405814.html
Python中命名空间与作用域使用总结:https://www.cnblogs.com/chenhuabin/p/10123009.html
一道题看Python的LEGB规则:https://www.ucloud.cn/yun/45499.html
Python LEGB规则:https://www.jianshu.com/p/3b72ba5a209c
python中的LEGB 规则:https://blog.csdn.net/xun527/article/details/76795328
python进阶系列
python进阶01偏函数
python进阶02yield
python进阶03UnboundLocalError和NameError错误
python进阶04IO的同步异步,阻塞非阻塞
python进阶04IO的同步异步,阻塞非阻塞
python进阶05并发之一基本概念
python进阶05并发之一基本概念
python进阶06并发之二技术点关键词
python进阶07并发之三其他问题
python进阶08并发之四map, apply, map_async, apply_async差异
python进阶09并发之五生产者消费者
python进阶10并发之六并行化改造
python进阶11并发之七多种并发方式的效率测试
python进阶12并发之八多线程与数据同步
python进阶13并发之九多进程和数据共享
python进阶14变量作用域LEGB
python进阶15多继承与Mixin
python进阶16炫技巧
python进阶17正则表达式
python进阶18垃圾回收GC
python进阶19装饰器和闭包
python进阶20之actor
python进阶21再识单例模式