深入理解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 10 Python
python中的闭包函数
Feb 09 Python
Python根据成绩分析系统浅析
Feb 11 Python
解决在pycharm运行代码,调用CMD窗口的命令运行显示乱码问题
Aug 23 Python
Python爬虫爬取煎蛋网图片代码实例
Dec 16 Python
Python log模块logging记录打印用法解析
Jan 20 Python
python连接mongodb集群方法详解
Feb 13 Python
Python datetime 格式化 明天,昨天实例
Mar 02 Python
读取nii或nii.gz文件中的信息即输出图像操作
Jul 01 Python
如何利用python读取micaps文件详解
Oct 18 Python
浅谈Python中对象是如何被调用的
Apr 06 Python
方法汇总:Python 安装第三方库常用
Apr 26 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的#1251问题
2006/11/25 PHP
php快速url重写 更新版[需php 5.30以上]
2010/04/20 PHP
php 获取百度的热词数据的代码
2012/02/18 PHP
thinkphp判断访客为手机端或PC端的方法
2014/11/24 PHP
ThinkPHP的SAE开发相关注意事项详解
2016/10/09 PHP
微信公众号开发之获取位置信息php代码
2018/06/13 PHP
语义化 H1 标签
2008/01/14 Javascript
jquery 3D 标签云示例代码
2014/06/12 Javascript
angularjs学习笔记之三大模块(modal,controller,view)
2015/09/26 Javascript
jQuery+Ajax+PHP+Mysql实现分页显示数据实例讲解
2015/09/27 Javascript
基于jQuery实现滚动切换效果
2016/12/02 Javascript
JavaScript变量类型以及变量作用域详解
2017/08/14 Javascript
vue打包后显示空白正确处理方法
2017/11/01 Javascript
Vue 项目分环境打包的方法示例
2018/08/03 Javascript
对vue中methods互相调用的方法详解
2018/08/30 Javascript
微信小程序开发之路由切换页面重定向问题
2018/09/18 Javascript
AngularJS 多指令Scope问题的解决
2018/10/25 Javascript
如何实现双向绑定mvvm的原理实现
2019/05/28 Javascript
微信小程序点击item使之滚动到屏幕中间位置
2020/03/25 Javascript
javascript实现滚轮轮播图片
2020/12/13 Javascript
[01:55]《走出家门看比赛》——DOTA2 2015国际邀请赛同城线下观战
2015/07/18 DOTA
python多进程操作实例
2014/11/21 Python
Python Web框架Flask中使用新浪SAE云存储实例
2015/02/08 Python
Python网络爬虫实例讲解
2016/04/28 Python
Python cookbook(数据结构与算法)找到最大或最小的N个元素实现方法示例
2018/02/13 Python
python如何通过实例方法名字调用方法
2018/03/21 Python
使用Python向C语言的链接库传递数组、结构体、指针类型的数据
2019/01/29 Python
python实现Excel文件转换为TXT文件
2019/04/28 Python
Python三元运算与lambda表达式实例解析
2019/11/30 Python
澳大利亚领先的在线美容商店:Facial Co
2017/10/22 全球购物
意大利灯具购物网站:Lampade.it
2018/10/18 全球购物
千禧酒店及度假村官方网站:Millennium Hotels and Resorts
2019/05/10 全球购物
程序集与命名空间有什么不同
2014/07/25 面试题
资产评估专业大学生求职信
2013/09/29 职场文书
入党积极分子十八届四中全会思想汇报
2014/10/23 职场文书
2015年个人招商工作总结
2015/04/25 职场文书