深入理解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抓取电影天堂电影信息的代码
Apr 07 Python
详解Python的Flask框架中生成SECRET_KEY密钥的方法
Jun 07 Python
Python的消息队列包SnakeMQ使用初探
Jun 29 Python
Python使用剪切板的方法
Jun 06 Python
python遍历序列enumerate函数浅析
Oct 17 Python
简单谈谈python中的lambda表达式
Jan 19 Python
vue.js实现输入框输入值内容实时响应变化示例
Jul 07 Python
tensorflow实现简单逻辑回归
Sep 07 Python
flask框架jinja2模板与模板继承实例分析
Aug 01 Python
手把手教你Python yLab的绘制折线图的画法
Oct 23 Python
使用Python项目生成所有依赖包的清单方式
Jul 13 Python
python中pandas对多列进行分组统计的实现
Jun 18 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
php md5下16位和32位的实现代码
2008/04/09 PHP
php smarty模版引擎中变量操作符及使用方法
2009/12/11 PHP
php图片处理函数获取类型及扩展名实例
2014/11/19 PHP
linux平台编译安装PHP7并安装Redis扩展与Swoole扩展实例教程
2016/09/30 PHP
javaScript复制功能调用实现方案
2012/12/13 Javascript
关于JavaScript中string 的replace
2013/04/12 Javascript
JQuery的AJAX实现文件下载的小例子
2013/05/15 Javascript
jQuery实现鼠标经过时出现隐藏层文字链接的方法
2015/10/12 Javascript
Google 地图叠加层实例讲解
2016/08/06 Javascript
jQuery图片前后对比插件beforeAfter用法示例【附demo源码下载】
2016/09/20 Javascript
如何实现json数据可视化详解
2016/11/24 Javascript
AngularJS常见过滤器用法实例总结
2017/07/06 Javascript
js插件实现图片滑动验证码
2020/09/29 Javascript
layer.open 按钮的点击事件关闭方法
2018/08/17 Javascript
vue项目从node8.x升级到12.x后的问题解决
2019/10/25 Javascript
解决vue-router 嵌套路由没反应的问题
2020/09/22 Javascript
[02:09]DOTA2辉夜杯 EHOME夺冠举杯现场
2015/12/28 DOTA
python字典排序实例详解
2015/05/20 Python
Python中字符串的处理技巧分享
2016/09/17 Python
Python表示矩阵的方法分析
2017/05/26 Python
Python通过Django实现用户注册和邮箱验证功能代码
2017/12/11 Python
Python使用pandas和xlsxwriter读写xlsx文件的方法示例
2019/04/09 Python
利用python实现汉字转拼音的2种方法
2019/08/12 Python
解决启动django,浏览器显示“服务器拒绝访问”的问题
2020/05/13 Python
Python map及filter函数使用方法解析
2020/08/06 Python
python 批量将中文名转换为拼音
2021/02/07 Python
微信小程序“圣诞帽”的实现思路详解
2017/12/28 HTML / CSS
ABOUT YOU匈牙利:500个最受欢迎的时尚品牌
2019/07/19 全球购物
俄罗斯Sportmarket体育在线商店:用于旅游和户外活动
2019/11/12 全球购物
怎样有效的进行自我评价
2013/10/06 职场文书
简历自我评价怎么写呢?
2014/01/06 职场文书
新护士岗前培训制度
2014/02/02 职场文书
《会变的花树叶》教学反思
2014/02/10 职场文书
寒假社会实践个人总结
2015/03/06 职场文书
简单且有用的Python数据分析和机器学习代码
2021/07/02 Python
从原生JavaScript到React深入理解
2022/07/23 Javascript