Python中的__builtin__和__builtins__

文章前言

这里主要以Python 2.7为例来探讨Python 2.x中__builtin__模块和__builtins__模块的区别和联系!

PS:在Python 3+中,__builtin__模块被命名为builtins

命名空间

名称空间(NameSpace)是Python中非常重要的一个概念,所谓命名空间其实就是从名称到对象的映射,大部分的命名空间都是通过Python 字典来实现的。

命名空间提供了在项目中避免名字冲突的一种方法,各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。

我们举一个计算机系统中的例子,一个文件夹(目录)中可以包含多个文件夹,每个文件夹中不能有相同的文件名,但不同文件夹中的文件可以重名:

一般有三种命名空间:

  • 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
  • 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
  • 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)

命名空间查找顺序:

假设我们要使用变量runoob,则Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间,如果找不到变量 runoob,它将放弃查找并引发一个 NameError 异常:

NameError: name 'runoob' is not defined

命名空间的生命周期:

命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束,因此,我们无法从外部命名空间访问内部命名空间的对象。

# var1 是全局名称
var1 = 5
def some_func(): 
  
	# var2 是局部名称
    var2 = 6
    def some_inner_func(): 
  
        # var3 是内嵌的局部名称
        var3 = 7

如下图所示,相同的对象名称可以存在于多个命名空间中:

内建函数

在启动Python解释器之后,即使没有创建任何的变量或者函数,还是会有许多函数可以使用,我们把这些函数称为内建函数,是因为它们不需要我们作任何定义,在启动Python解释器的时候,就已经导入到内存当中供我们使用:

内置名称与__builtins__

内建函数也是函数,虽然我们没有人为导入这些,但是正如前面所说,在启动Python解释器的时候,会自动帮我们导入,那么内建函数存在于哪里呢?

其实准确地来说,是Python解释器在启动的时候会首先加载内建名称空间,内建名称空间有许多名字到对象之间映射,而这些名字其实就是内建函数的名称,对象就是这些内建函数本身(注意区分函数名称和函数对象的区别),这些名称空间由__builtins__模块中的名字构成。

下面我们在一个空文件里通过打印dir()来查看被自动导入的模块都有哪些:

可以看到有一个__builtins__的模块名称,这个模块本身定义了一个名称空间,即内建名称空间,我们不妨dir一下:

会看到我们熟悉的内建函数的名称,如list、dict等,当然还有一些异常和其它属性~

__builtins__与__builtin__

既然内建名称空间由__builtins__模块中的名称空间定义,那么是不是也意味着内建名称空间中所对应的这些函数也是在__builtins__模块中实现的呢?显然不是的,我们可以在解释器中直接输入__builtins__:

从结果中可以看到,__builtins__其实还是引用了__builtin__模块而已,这说明真正的模块是__builtin__,也就是说,前面提到的内建函数其实是在内建模块__builtin__中定义的,即__builtins__模块包含内建名称空间中内建名字的集合(因为它引用或者说指向了__builtin__模块),而真正的内建函数、异常和属性来自__builtin__模块,也就是说,在Python中,其实真正是只有__builtin__这个模块,并不存在__builtins__这个模块:

可以看到,导入__builtin__模块并没有问题,但导入__builtins__模块时就会提示不存在,这充分说明了前面的结论。

__builtins__与__builtin__研究

上面只是大概说了下__builtins__与__builtin__两个模块的简单区分而已,其实深究下去,要分成下面所提及的两种情况。

在主模块__main__中

其实我们在使用Python交互器的时候就是在主模块中进行操作,可以做如下验证:

在这种情况,__builtins__与__builtin__是完全一样的,它们指向的都是__builtin__这个内建模块:

从上面的结果可以看到,这时候__builtins__和__builtin__是完全一样的,它们都指向了同一个模块对象,这也就是Python中引用传递的概念,其实这种情况跟我们创建一个变量并对它做一次引用传递时的情况是一样的。

不在主模块__main__中

如果不是在主模块中使用__builtins__,这时候__builtins__只是对__builtin__.__dict__的一个简单引用而已,可以通过下面的测试来验证说明:

先创建一个test.py模块,代码如下所示:

import __builtin__
 
print 'Module name:', __name__
 
print '*==test __builtin__ and __builtins__==*'
print '__builtin__ == __builtins__', __builtin__ == __builtins__
print '__builtin__ is __builtins__', __builtin__ is __builtins__
print 'id(__builtin__)', id(__builtin__)
print 'id(__builtins__)', id(__builtins__)
 
print '=' * 50
 
print '*==test __builtin__.__dict__ and __builtins__==*'
print '__builtin__.__dict__ == __builtins__', __builtin__.__dict__ == __builtins__
print '__builtin__.__dict__ is __builtins__', __builtin__.__dict__ is __builtins__
print 'id(__builtin__)', id(__builtin__.__dict__)
print 'id(__builtins__)', id(__builtins__)

之后我们在Python交互器中导入它,那么这时候对于test模块来说,它就不是主模块了:

可以看到输出的结果跟我们想的是完全一样的,这时候__builtins__其实是对__builtin__.__dict__模块的引用

文末总结

在启动Python解释器或运行一个Python程序时,内建名称空间都是从__builtins__模块中加载的,只是__builtins__本身是对Python内建模块__builtin__的引用,而这种引用又分下面两种情况:

  • 如果是在主模块__main__中,__builtins__直接引用__builtin__模块,此时模块名__builtins__与模块名__builtin__指向的都是同一个模块,即<builtin>内建模块(这里要注意变量名和对象本身的区别) 
  • 如果不是在主模块中,那么__builtins__只是引用了__builtin__.__dict__

 

参考链接:

https://docs.python.org/3/library/functions.html#abs

https://www.runoob.com/python3/python3-namespace-scope.html

https://blog.csdn.net/pzqingchong/article/details/77366084

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FLy_鹏程万里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值