深入理解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 相关文章推荐
tornado捕获和处理404错误的方法
Feb 26 Python
python网络编程学习笔记(五):socket的一些补充
Jun 09 Python
举例详解Python中循环语句的嵌套使用
May 14 Python
Python设计模式之MVC模式简单示例
Jan 10 Python
删除python pandas.DataFrame 的多重index实例
Jun 08 Python
Python 中如何实现参数化测试的方法示例
Dec 10 Python
vue常用指令代码实例总结
Mar 16 Python
利用4行Python代码监测每一行程序的运行时间和空间消耗
Apr 22 Python
浅析python 动态库m.so.1.0错误问题
May 09 Python
重构Python代码的六个实例
Nov 25 Python
python 递归相关知识总结
Mar 03 Python
python保存图片的四个常用方法
Feb 28 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
jquery下将选择的checkbox的id组成字符串的方法
2010/11/28 Javascript
js中eval详解
2012/03/30 Javascript
圣诞节Merry Christmas给博客添加浪漫的下雪效果基于jquery实现
2012/12/27 Javascript
JS代码判断IE6,IE7,IE8,IE9的函数代码
2013/08/02 Javascript
jquery获取URL中参数解决中文乱码问题的两种方法
2013/12/18 Javascript
IE6 hack for js 集锦
2014/09/23 Javascript
通过javascript进行UTF-8编码的实现方法
2016/06/27 Javascript
JavaScript中闭包的写法和作用详解
2016/06/29 Javascript
利用JS屏蔽页面中的Enter按键提交表单的方法
2016/11/25 Javascript
canvas快速绘制圆形、三角形、矩形、多边形方法介绍
2016/12/29 Javascript
Angularjs过滤器实现动态搜索与排序功能示例
2017/12/13 Javascript
JavaScript 实现同时选取多个时间段的方法
2019/10/17 Javascript
解决vue中el-tab-pane切换的问题
2020/07/19 Javascript
谈谈Python进行验证码识别的一些想法
2016/01/25 Python
Python使用win32 COM实现Excel的写入与保存功能示例
2018/05/03 Python
pandas通过loc生成新的列方法
2018/11/28 Python
Python实现查找字符串数组最长公共前缀示例
2019/03/27 Python
python实现beta分布概率密度函数的方法
2019/07/08 Python
Django实现从数据库中获取到的数据转换为dict
2020/03/27 Python
VSCode基础使用与VSCode调试python程序入门的图文教程
2020/03/30 Python
python实现画图工具
2020/08/27 Python
澳大利亚足球鞋和服装购物网站:Ultra Football
2018/10/11 全球购物
香港百佳网上超级市场:PARKNSHOP.com
2020/06/10 全球购物
JSP和EJB可以共享HttpSession么?EJB里面可以改变session里面的内容
2013/06/05 面试题
往来会计岗位职责
2013/12/19 职场文书
《阳光》教学反思
2014/02/23 职场文书
石油工程专业毕业生求职信
2014/04/13 职场文书
农村党员一句话承诺
2014/05/30 职场文书
总经理任命书范本
2014/06/05 职场文书
党支部书记四风问题整改措施
2014/09/24 职场文书
群众路线个人剖析材料
2014/10/07 职场文书
个人批评与自我批评总结
2014/10/17 职场文书
格列佛游记读书笔记
2015/06/30 职场文书
2019年员工晋升管理制度范本!
2019/07/08 职场文书
python第三方网页解析器 lxml 扩展库与 xpath 的使用方法
2021/04/06 Python
python manim实现排序算法动画示例
2022/08/14 Python