深入理解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 相关文章推荐
DJANGO-ALLAUTH社交用户系统的安装配置
Nov 18 Python
Python多线程编程(五):死锁的形成
Apr 05 Python
Python读取本地文件并解析网页元素的方法
May 21 Python
python3 拼接字符串的7种方法
Sep 12 Python
Python+PyQT5的子线程更新UI界面的实例
Jun 14 Python
详解python和matlab的优势与区别
Jun 28 Python
python requests指定出口ip的例子
Jul 25 Python
解决django model修改添加字段报错的问题
Nov 18 Python
Python第三方库的几种安装方式(小结)
Apr 03 Python
pycharm激活方法到2099年(激活流程)
Sep 22 Python
python爬取天气数据的实例详解
Nov 20 Python
Python re.sub 反向引用的实现
Jul 07 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生成随机字符串可指定纯数字、纯字母或者混合的
2014/04/18 PHP
关于PHP中协程和阻塞的一些理解与思考
2017/08/11 PHP
Javascript 获取滚动条位置等信息的函数
2009/09/08 Javascript
Javascript 浮点运算精度问题分析与解决
2014/03/26 Javascript
javascript实现完美拖拽效果
2015/05/06 Javascript
javascript封装的sqlite操作类实例
2015/07/17 Javascript
javascript封装简单实现方法
2015/08/11 Javascript
JS中常用的输出方式(五种)
2016/06/12 Javascript
jQuery实现立体式数字动态增加(animate方法)
2016/12/21 Javascript
纯JS实现表单验证实例
2016/12/24 Javascript
超全面的javascript中变量命名规则
2017/02/09 Javascript
jQuery、zepto、js常用小技巧
2017/02/12 Javascript
nodejs入门教程二:创建一个简单应用示例
2017/04/24 NodeJs
详解vue-cli之webpack3构建全面提速优化
2017/12/25 Javascript
vue的一个分页组件的示例代码
2017/12/25 Javascript
浅谈Node.js爬虫之网页请求模块
2018/01/11 Javascript
vue form 表单提交后刷新页面的方法
2018/09/04 Javascript
vue配置font-awesome5的方法步骤
2019/01/27 Javascript
ES10 特性的完整指南小结
2019/03/04 Javascript
JS实现页面侧边栏效果探究
2021/01/08 Javascript
调试Python程序代码的几种方法总结
2015/04/28 Python
linux下python抓屏实现方法
2015/05/22 Python
python实现趣味图片字符化
2019/04/30 Python
python 获取sqlite3数据库的表名和表字段名的实例
2019/07/17 Python
Python局部变量与全局变量区别原理解析
2020/07/14 Python
联想哥伦比亚网上商城:Lenovo Colombia
2017/01/10 全球购物
公司人力资源的自我评价
2014/01/02 职场文书
代理协议书范本
2014/04/22 职场文书
学校节能减排倡议书
2014/05/16 职场文书
关于安全的广播稿
2014/10/23 职场文书
上课说话检讨书
2015/01/27 职场文书
2016春季运动会开幕词
2016/03/04 职场文书
详解nginx.conf 中 root 目录设置问题
2021/04/01 Servers
python numpy中setdiff1d的用法说明
2021/04/22 Python
jquery插件实现代码雨特效
2021/04/24 jQuery
自从在 IDEA 中用了热部署神器 JRebel 之后,开发效率提升了 10(真棒)
2021/06/26 Java/Android