深入理解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 03 Python
Python编写百度贴吧的简单爬虫
Apr 02 Python
python requests爬取高德地图数据的实例
Nov 10 Python
用scikit-learn和pandas学习线性回归的方法
Jun 21 Python
numpy求平均值的维度设定的例子
Aug 24 Python
python numpy存取文件的方式
Apr 01 Python
python实现引用其他路径包里面的模块
Mar 09 Python
python七种方法判断字符串是否包含子串
Aug 18 Python
Python列表推导式实现代码实例
Sep 09 Python
pycharm中leetcode插件使用图文详解
Dec 07 Python
Python利用folium实现地图可视化
May 23 Python
详解Python函数print用法
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循环检测目录是否存在并创建(循环创建目录)
2011/01/06 PHP
PHP可逆加密/解密函数分享
2012/09/25 PHP
实现PHP多线程异步请求的3种方法
2014/01/17 PHP
phpStudy2016 配置多个域名期间遇到的问题小结
2017/10/19 PHP
PHP删除数组中指定下标的元素方法
2018/02/03 PHP
php中yii框架实例用法
2020/12/22 PHP
【消息提示组件】,兼容IE6/7&amp;&amp;FF2
2007/09/04 Javascript
javascript中onmouse事件在div中失效问题的解决方法
2012/01/09 Javascript
jqPlot 图表中文API使用文档及源码和在线示例
2012/02/07 Javascript
JS操作数据库的实例代码
2013/10/17 Javascript
利用原生JS自动生成文章标题树的实例
2016/08/22 Javascript
Jquery Easyui选项卡组件Tab使用详解(10)
2016/12/18 Javascript
js 性能优化之算法和流程控制
2017/02/15 Javascript
js随机生成一个验证码
2017/06/01 Javascript
详解jquery选择器的原理
2017/08/01 jQuery
vuejs实现递归树型菜单组件
2018/01/13 Javascript
vue自定义指令directive实例详解
2018/01/17 Javascript
JavaScript遍历查找数组中最大值与最小值的方法示例
2019/05/24 Javascript
ES6 Promise对象的含义和基本用法分析
2019/06/14 Javascript
微信小程序选择图片控件
2021/01/19 Javascript
python正则表达式抓取成语网站
2013/11/20 Python
python基于itchat模块实现微信防撤回
2019/04/29 Python
Django ORM 查询管理器源码解析
2019/08/05 Python
python add_argument()用法解析
2020/01/29 Python
浅谈spring boot 集成 log4j 解决与logback冲突的问题
2020/02/20 Python
Python调用JavaScript代码的方法
2020/10/27 Python
HTML+CSS3+JS 实现的下拉菜单
2020/11/25 HTML / CSS
沙特阿拉伯网上购物:Sayidaty Mall
2018/05/06 全球购物
Dodax奥地利:音乐、电影、书籍、玩具、电子产品等
2019/08/31 全球购物
总裁办公室主任职责
2014/01/02 职场文书
内业资料员岗位职责
2014/01/04 职场文书
给老师的检讨书
2014/02/11 职场文书
房屋买卖协议书
2014/04/10 职场文书
施工单位安全责任书
2014/07/24 职场文书
房屋租房协议书范本
2014/12/04 职场文书
Python函数中的不定长参数相关知识总结
2021/06/24 Python