转载

python 模块加载

python 模块加载

本文主要介绍python模块加载的过程。

module的组成

所有的module都是由对象和对象之间的关系组成。

type和object

python中所有的东西都是对象,分为三类:类型type、类class和实例instance。

三种对象之间的两种关系:

  • is kind of,基类和子类的关系
  • is instance of,类和对象的关系

类和对象的关系可以通过内建方法 type 来辨别。

python中,任何一个类都是直接或间接继承自object,而每一个对象都会拥有自己的type类型,可以通过__class__属性获得。

运行环境初始化

python首先需要加载多个基础的module,例如__builtin__,sys等,同时也会完成python类型系统的初始化和异常系统的初始化。

系统module初始化

Python内部维护了一个维护加载到内存的module集合,需要现在集合中查找module是否存在。如果存在直接返回该module对象,否则创建该module对象,并插入到module集合中。创建module后,需要设置module的属性。

由于python的module集合是一个PyDictObject对象,而PyDictObject对象在Python中是一个可变对象,所以其中维护的元素有可能在运行时被删除。对于Python的扩展module,例如sys,为了避免再一次初始化同样的module,python将所有的扩展module通过一个全局的PyDictObject对象来进行备份维护。

启动虚拟机

python包括两种运行方式:命令行和脚本文件。

python中的run_mode函数基于AST抽象语法树 (AST, Abstract Syntax Tree)完成了字节码的编译工作,并创建PyCodeObject对象。

python中所有的线程都是共享同样的builtin名字空间。

模块的动态加载

import功能包括:

  • python运行时的全局module缓存的维护和搜索;
  • 解析和搜索module路径的树形结构;
  • 对不同文件格式的module动态加载机制。

py文件中的import不会影响上一层的命名空间,只会影响各自的命名空间,也就是影响各自module自身维护的那个dict对象。但所有的import操作都会影响全局的module集合,这样的话只要再一次import该module,python虚拟机只需要将全局module集合中缓存的对象返回。

在module的基础之上,python提供了package机制(逻辑相关联的module需要聚合到同一package中)。也就是说通过package机制来管理module,通过module来管理class。

文件件中存在__init__.py文件才能成为package(多个py文件组成的文件夹)。

在加载package下的module时,例如a.b.c,python内部将这个module视为一个树形结构,c是b的子节点,b是a的子节点。python虚拟机在动态加载时,需要将这个树形结构分解,然后从左到右依次去sys.modules中查找每一个符号是否存在。如果已经存在,假设存在a,那么在a对应的PyModuleObject对象中保持着__path__路径信息,此时就可以在a.__path__路径中搜索b和c了。

del删除模块只是把模块从当前命名空间中删除,但该module依然存在于module缓存中。

module缓存

python中的全局module集合sys.modules被称为modules缓存,保证了module的唯一性,每当有import操作都会在该sys.modules查找,如果不存在就会将该module加入到sys.modules中。

如果已经加载的模块发生改变,那么需要调用 reload 函数来重新加载该模块。需要注意reload函数并不会重新创建该对象,而在在原有对象的基础上做修改。

正文到此结束
Loading...