深入理解Python中命名空间的查找规则LEGB


Posted in Python onAugust 06, 2015

名字空间

Python 的名字空间是 Python 一个非常核心的内容。
其他语言中如 C 中,变量名是内存地址的别名,而在 Python 中,名字是一个字符串对象,它与他指向的对象构成一个{name:object}关联。
Python 由很多名字空间,而 LEGB 则是名字空间的一种查找规则。
作用域

Python 中name-object的关联存储在不同的作用域中,各个不同的作用域是相互独立的。而我们就在不同的作用域中搜索name-object。

举个栗子,来说明作用域是相互独立的。

In [11]: i = "G"

In [12]: def test():
      i = "L"
      print i, "in locals"
  ....:

In [13]: test()
    L in locals

In [14]: print i, "in globals"
    G in globals

 

在上面的栗子中,我们定义了两次 i,在 test 函数中是 i-L,在外面是 i-G。为什么在 test 函数中,我们 i 指向的是对象 L,而在外面,i 指向的则是 G?这就是 LEGB 的作用。
简述

简而言之,LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__

  •     locals 是函数内的名字空间,包括局部变量和形参
  •     enclosing 外部嵌套函数的名字空间(闭包中常见)
  •     globals 全局变量,函数定义所在模块的名字空间
  •     builtins 内置模块的名字空间

所以,在 Python 中检索一个变量的时候,优先回到 locals 里面来检索,检索不到的情况下会检索 enclosing ,enclosing 没有则到 globals 全局变量里面检索,最后是到 builtins 里面来检索。

当然,因为 builtins 的特殊性,我们可以直接在 builtins 里面添加变量,这样就可以在任意模块中访问变量,不过这种方法太过于变态,不推荐这么做。
locals,globals

函数的形参跟内部变量都存储在 locals 中。

In [1]: def f(x):
  ...:   a = x
  ...:   print a
  ...:   print locals()
  ...:


In [2]: f("hello")
hello
{'a': 'hello', 'x': 'hello'}

不过在函数内部调用global 声明的时候,可以将变量存储在 globals 中

In [6]: def f(x):
  ...:   global a
  ...:   a = x
  ...:   print a
  ...:   print locals()
  ...:

In [7]: f("hello")
hello
{'x': 'hello'}

In [8]: print a
hello

In [9]: print x
---------------------------------------------------------------------------
NameError                 Traceback (most recent call last)
<ipython-input-9-2d264e11d975> in <module>()
----> 1 print x

NameError: name 'x' is not defined

如上面栗子中那样,在函数中声明 a 为全局变量,则函数 f 的 locals只有参数 x,而没有变量,而在外部可以使用变量 a,而使用 x 的时候则是NameError
Enclosed

Enclosing 是外部嵌套函数的名字空间。我们经常在闭包中用到。在 Python3中提供了一个 nonlocal关键字来修改外部嵌套函数的名字空间,但是要使用 Python3才有,我等使用 Python2的只能眼馋一下。

In [11]: def outer():
  ....:   a_var = 'enclosed value'
  ....:   print a_var
  ....:   def inner():
  ....:     a_var = 'local value'
  ....:     print(a_var)
  ....:   inner()
  ....:   print a_var
  ....:

In [12]: outer()
enclosed value
local value
enclosed value

下面的栗子简单示范一下 nonlocal 的用法,实在 Python3下面才可以正常运行的:

In [1]: a_var = 'global value'

In [2]: def outer():
  ...:   a_var = "local value"
  ...:   print("outer befor", a_var)
  ...:   def inner():
  ...:     nonlocal a_var
  ...:     a_var = "inner value"
  ...:     print("in inner():", a_var)
  ...:   inner()
  ...:   print("outer inner:", a_var)
  ...:

In [3]: outer()
outer befor local value
in inner(): inner value
outer inner: inner value

In [4]: print(a_var)
global value

builtins

builtins 则是内置模块,轻易不要修改

In [19]: b
---------------------------------------------------------------------------
NameError                 Traceback (most recent call last)
<ipython-input-19-3b5d5c371295> in <module>()
----> 1 b

NameError: name 'b' is not defined

In [20]: __builtins__.b = "builtins"

In [21]: b
Out[21]: 'builtins'

上面栗子中在第一次调用b的时候报错NameError,之后我们修改 builtins 的名字空间,将名字b与值"builtins"进行关联,就可以正常调用了。这种非常规用法不建议使用。

Python 相关文章推荐
python正则表达式re模块详解
Jun 25 Python
Python日志模块logging简介
Apr 13 Python
归纳整理Python中的控制流语句的知识点
Apr 14 Python
Python实现数通设备端口使用情况监控实例
Jul 15 Python
Python打印输出数组中全部元素
Mar 13 Python
pandas获取groupby分组里最大值所在的行方法
Apr 20 Python
python3射线法判断点是否在多边形内
Jun 28 Python
Django如何使用jwt获取用户信息
Apr 21 Python
详解numpy1.19.4与python3.9版本冲突解决
Dec 15 Python
Python爬虫回测股票的实例讲解
Jan 22 Python
python学习之使用Matplotlib画实时的动态折线图的示例代码
Feb 25 Python
python如何读取和存储dict()与.json格式文件
Jun 25 Python
举例详解Python中yield生成器的用法
Aug 05 #Python
Python中return语句用法实例分析
Aug 04 #Python
python函数形参用法实例分析
Aug 04 #Python
Python简明入门教程
Aug 04 #Python
将Python代码打包为jar软件的简单方法
Aug 04 #Python
python函数局部变量用法实例分析
Aug 04 #Python
python删除列表内容
Aug 04 #Python
You might like
for循环连续求和、九九乘法表代码
2012/02/20 PHP
php版本的cron定时任务执行器使用实例
2014/08/19 PHP
几个实用的PHP内置函数使用指南
2014/11/27 PHP
PHP读取文件内容的五种方式
2015/12/28 PHP
Zend Framework教程之配置文件application.ini解析
2016/03/10 PHP
php传值方式和ajax的验证功能
2017/03/27 PHP
php的对象传值与引用传值代码实例讲解
2021/02/26 PHP
javascript new后的constructor属性
2010/08/05 Javascript
jquery选择器的选择使用及性能介绍
2013/01/16 Javascript
E3 tree 1.6在Firefox下显示问题的修复方法
2013/01/30 Javascript
jQuery处理xml格式的返回数据(实例解析)
2013/11/28 Javascript
javascript校验价格合法性实例(必须输入2位小数)
2014/05/05 Javascript
jQuery中slideUp 和 slideDown 的点击事件
2015/02/26 Javascript
详解JavaScript对象类型
2016/06/16 Javascript
AngularJS优雅的自定义指令
2016/07/01 Javascript
简洁实用的BootStrap jQuery手风琴插件
2016/08/31 Javascript
关于Jquery中的bind(),on()绑定事件方式总结
2016/10/26 Javascript
Angularjs实现页面模板清除的方法
2018/07/20 Javascript
浅谈Angular7 项目开发总结
2018/12/19 Javascript
如何在Angular8.0下使用ngx-translate进行国际化配置
2019/07/24 Javascript
JavaScript代理模式原理与用法实例详解
2020/03/10 Javascript
vue中echarts图表大小适应窗口大小且不需要刷新案例
2020/07/19 Javascript
vue 实现element-ui中的加载中状态
2020/11/11 Javascript
Python实现将xml导入至excel
2015/11/20 Python
python3.6 +tkinter GUI编程 实现界面化的文本处理工具(推荐)
2017/12/20 Python
Pipenv一键搭建python虚拟环境的方法
2018/05/22 Python
对Python中for复合语句的使用示例讲解
2018/11/01 Python
Python编程深度学习计算库之numpy
2018/12/28 Python
python 去除二维数组/二维列表中的重复行方法
2019/01/23 Python
CSS3中的opacity属性使用教程
2015/08/19 HTML / CSS
canvas探照灯效果的示例代码
2018/11/30 HTML / CSS
Lampegiganten丹麦:欧洲领先的照明网上商店
2018/04/25 全球购物
请用用Java代码写一个堆栈
2012/01/26 面试题
党的群众路线教育实践活动个人整改方案
2014/09/21 职场文书
房屋财产继承协议书范本
2014/11/03 职场文书
疑《守望先锋2》A测截图泄露 或将推出新模式、新界面
2022/04/03 其他游戏