深入理解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脚本操作文件的小示例分享
Aug 27 Python
详解python里使用正则表达式的全匹配功能
Oct 19 Python
Pyinstaller将py打包成exe的实例
Mar 31 Python
python实现旋转和水平翻转的方法
Oct 25 Python
python执行CMD指令,并获取返回的方法
Dec 19 Python
python使用KNN算法识别手写数字
Apr 25 Python
一文了解Python并发编程的工程实现方法
May 31 Python
Django接收post前端返回的json格式数据代码实现
Jul 31 Python
Python callable内置函数原理解析
Mar 05 Python
Django DRF APIView源码运行流程详解
Aug 17 Python
PIP和conda 更换国内安装源的方法步骤
Sep 21 Python
Python捕获、播放和保存摄像头视频并提高视频清晰度和对比度
Apr 14 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 和 MySQL 时区的一点总结
2008/03/26 PHP
PHP7 新特性详细介绍
2016/09/06 PHP
Laravel 5.4.36中session没有保存成功问题的解决
2018/02/19 PHP
php+ajax实现文件切割上传功能示例
2020/03/03 PHP
PHP内存溢出优化代码详解
2021/02/26 PHP
jQuery源码分析-02正则表达式 RegExp 常用正则表达式
2011/11/14 Javascript
ie8本地图片上传预览示例代码
2014/01/12 Javascript
Nodejs+express+html5 实现拖拽上传
2014/08/08 NodeJs
JS中如何判断传过来的JSON数据中是否存在某字段
2014/08/18 Javascript
js实现iGoogleDivDrag模块拖动层拖动特效的方法
2015/03/04 Javascript
Select下拉框模糊查询功能实现代码
2016/07/22 Javascript
js实现九宫格的随机颜色跳转
2017/02/19 Javascript
整理关于Bootstrap表单的慕课笔记
2017/03/29 Javascript
Three.js的使用及绘制基础3D图形详解
2017/04/27 Javascript
微信小程序request请求后台接口php的实例详解
2017/09/20 Javascript
关于在vue 中使用百度ueEditor编辑器的方法实例代码
2018/09/14 Javascript
JavaScript ES6箭头函数使用指南
2018/12/30 Javascript
深入浅出 Vue 系列 -- 数据劫持实现原理
2019/04/23 Javascript
JavaScript中工厂函数与构造函数示例详解
2019/05/06 Javascript
小程序实现tab标签页
2020/11/16 Javascript
[38:23]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS LGD第一场
2014/05/24 DOTA
win7安装python生成随机数代码分享
2013/12/27 Python
Python使用requests提交HTTP表单的方法
2018/12/26 Python
基于Tensorflow使用CPU而不用GPU问题的解决
2020/02/07 Python
naturalizer加拿大官网:美国娜然女鞋
2017/04/04 全球购物
玩具反斗城天猫官方旗舰店:享誉全球的玩具店
2017/10/10 全球购物
在购买印度民族服饰:Soch
2020/09/15 全球购物
美国最大的购物网站:Amazon.com(亚马逊美国)
2020/05/23 全球购物
会计实习生自我鉴定
2013/12/12 职场文书
会计职业生涯规划书
2014/01/13 职场文书
职工小家建设活动方案
2014/08/25 职场文书
高中生学习计划书
2014/09/15 职场文书
2015年教育实习工作总结
2015/04/24 职场文书
2015年幼儿园学期工作总结
2015/05/22 职场文书
高中运动会广播稿
2015/08/19 职场文书