深入理解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发送邮件示例(支持中文邮件标题)
Feb 16 Python
Python读取mp3中ID3信息的方法
Mar 05 Python
python如何查看系统网络流量的信息
Sep 12 Python
Python绘制3D图形
May 03 Python
python pandas中对Series数据进行轴向连接的实例
Jun 08 Python
Python帮你微信头像任意添加装饰别再@微信官方了
Sep 25 Python
python pygame实现球球大作战
Nov 25 Python
Python中顺序表原理与实现方法详解
Dec 03 Python
python如何使用socketserver模块实现并发聊天
Dec 14 Python
使用python处理题库表格并转化为word形式的实现
Apr 14 Python
python数据分析之用sklearn预测糖尿病
Apr 22 Python
python实现对doc、txt、xls等文档的读写操作
Apr 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
跟我学小偷程序之成功偷取首页(第三天)
2006/10/09 PHP
php的list()的一步操作给一组变量进行赋值的使用
2011/05/18 PHP
Zend的MVC机制使用分析(二)
2013/05/02 PHP
三种php连接access数据库方法
2013/11/11 PHP
php 检查电子邮件函数(自写)
2014/01/16 PHP
PHP 的比较运算与逻辑运算详解
2016/05/12 PHP
JavaScript 页面坐标相关知识整理
2010/01/09 Javascript
jQuery 遍历json数组的实现代码
2020/09/22 Javascript
一个网马的tips实现分析
2010/11/28 Javascript
jQuery 名称冲突的解决方法
2011/04/08 Javascript
JavaScript登录验证码的实现
2016/10/27 Javascript
vue.js绑定class和style样式(6)
2016/12/09 Javascript
微信小程序 scroll-view隐藏滚动条详解
2017/01/16 Javascript
最全的JavaScript开发工具列表 总有一款适合你
2017/06/29 Javascript
详解Vue路由History mode模式中页面无法渲染的原因及解决
2017/09/28 Javascript
详解 vue.js用法和特性
2017/10/15 Javascript
Element Input组件分析小结
2018/10/11 Javascript
javascript跳转与返回和刷新页面的实例代码
2019/11/20 Javascript
[56:20]LGD vs VP Supermajor 败者组决赛 BO3 第三场 6.10
2018/07/04 DOTA
Python线程的两种编程方式
2015/04/14 Python
python解决Fedora解压zip时中文乱码的方法
2016/09/18 Python
Django中自定义查询对象的具体使用
2019/10/13 Python
如何用Python来进行查询和替换一个文本字符串
2014/01/02 面试题
应用英语专业自荐信
2014/01/26 职场文书
DIY手工制作经营店创业计划书
2014/02/01 职场文书
明信片寄语大全
2014/04/08 职场文书
幼儿园教师演讲稿
2014/05/06 职场文书
销售队伍口号
2014/06/11 职场文书
办公室主任岗位职责
2015/01/31 职场文书
餐厅收银员岗位职责
2015/04/07 职场文书
女性健康知识讲座通知
2015/04/23 职场文书
初一年级组工作总结
2015/08/12 职场文书
修辞手法有哪些?
2019/08/29 职场文书
Python生成九宫格图片的示例代码
2021/04/14 Python
python爬取网页版QQ空间,生成各类图表
2021/06/02 Python
JVM的类加载器和双亲委派模式你了解吗
2022/03/13 Java/Android