深入理解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实现端口复用实例代码
Jul 03 Python
Python通过PIL获取图片主要颜色并和颜色库进行对比的方法
Mar 19 Python
对于Python的框架中一些会话程序的管理
Apr 20 Python
使用Python中的tkinter模块作图的方法
Feb 07 Python
Python实现发送QQ邮件的封装
Jul 14 Python
详解Python自建logging模块
Jan 29 Python
windows下 兼容Python2和Python3的解决方法
Dec 05 Python
python 魔法函数实例及解析
Sep 25 Python
wxpython自定义下拉列表框过程图解
Feb 14 Python
Python实现爬取网页中动态加载的数据
Aug 17 Python
python基本算法之实现归并排序(Merge sort)
Sep 01 Python
Python实现钉钉/企业微信自动打卡的示例代码
Feb 02 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
PHPMyadmin 配置文件详解(配置)
2009/12/03 PHP
PHP下常用正则表达式整理
2010/10/26 PHP
浅析PHP页面局部刷新功能的实现小结
2013/06/21 PHP
PHP使用缓存即时输出内容(output buffering)的方法
2015/08/03 PHP
PHP基于Redis消息队列实现发布微博的方法
2017/05/03 PHP
laravel 实现用户登录注销并限制功能
2019/10/24 PHP
关于javascript中的typeof和instanceof介绍
2012/12/04 Javascript
JavaScript中数组对象的那些自带方法介绍
2013/03/12 Javascript
jquery分页对象使用示例
2014/04/01 Javascript
纯js代码实现简单计算器
2015/12/02 Javascript
JavaScript位移运算符(无符号) &gt;&gt;&gt; 三个大于号 的使用方法详解
2016/03/31 Javascript
基于JQuery打造无缝滚动新闻步骤详解
2016/03/31 Javascript
jQuery DateTimePicker 日期和时间插件示例
2017/01/22 Javascript
jQuery实现图片滑动效果
2017/03/08 Javascript
JS使用正则表达式找出最长连续子串长度
2017/10/26 Javascript
详解react-redux插件入门
2018/04/19 Javascript
VSCode搭建React Native环境
2020/05/07 Javascript
用python写asp详细讲解
2013/12/16 Python
Python实现简单字典树的方法
2016/04/29 Python
在CentOS上配置Nginx+Gunicorn+Python+Flask环境的教程
2016/06/07 Python
python语言基本语句用法总结
2019/06/11 Python
更新pip3与pyttsx3文字语音转换的实现方法
2019/08/08 Python
详解Python3 pickle模块用法
2019/09/16 Python
如何基于Python实现自动扫雷
2020/01/06 Python
Django 用户登陆访问限制实例 @login_required
2020/05/13 Python
Python unittest如何生成HTMLTestRunner模块
2020/09/08 Python
python eventlet绿化和patch原理
2020/11/21 Python
python 对象真假值的实例(哪些视为False)
2020/12/11 Python
python函数超时自动退出的实操方法
2020/12/28 Python
完美解决torch.cuda.is_available()一直返回False的玄学方法
2021/02/06 Python
澳大利亚设计的婴儿和女孩的衣服:Oobi
2018/12/16 全球购物
小学社团活动总结
2014/06/27 职场文书
收银员岗位职责
2015/02/03 职场文书
见习期个人总结
2015/03/05 职场文书
初中历史教学反思
2016/02/19 职场文书
导游词之河北野三坡
2019/12/11 职场文书