python模块导入详解
目录
包和模块
模块导入
绝对导入
sys.modules
sys.meta_path
sys.path
相对导入
__init__.py相对导入
mian脚本中的相对导入
Reference
包和模块
我们可以在一个脚本中定义变量、函数和类,并添加逻辑,但是当某个项目具有复杂的逻辑时,我们希望把这些逻辑分解成不同的脚本,并以一定的合理的方式组织成层级结构,这种具有层级结构的包含脚本的文件夹就称为包。
模块通常指的是定义了变量、函数和类的脚本。但是实际上,包也属于模块的一种,区分一个模块到底是包还是某个具体的脚本,就看该模块是否具有__path__属性,具有__path__属性的模块称为包,没有__path__属性的模块就是我们最长见到的常规脚本。
在python3.3之前,要组成一个包,还必须在顶层目录开始,每一层结构目录中,都必须包含__init__.py文件,但是在python3.3开始,可以没有__init__.py文件。上述中,当我们说包是模块时,我们说的这个包指的就是其目录下的__init__.py初始化文件,这一点,可以通过在_init__.py中打印出__name__属性验证,即__init__.py文件的__name__属性就是对应的包名。
模块导入
当导入一个模块时,该模块会被执行,当模块是一个包时,根据上述,该包实际上就是该包下的__init__.py文件,所以导入包时,该包对应的__init__.py文件会被执行。当进行类似import A.B.C或者from A.B import C的导入时,会依次执行A、B下的初始化文件,当然如果C依然是一个子包的话,C下的初始化文件也会被执行。
这里需要强调一下import语句和from xxx import yyy语句的一点重要区别,import语句后面跟随的必须是模块,但是from xxx import yyy语句中,yyy不一定是模块,也可以是变量、函数或者类。
模块导入的方式分为绝对导入和相对导入。
绝对导入
在python3开始,绝对导入指的就是import A或者from A import B这种语句。那么,当python在执行import A语句或者from A import B语句时,背后到底做了哪些事情呢?即python到底时如何去查找对应的模块的呢?
sys.modules
首先,由于启动python解释器时,python会自己预导入一些内置和标准模块,并把这些被导入的模块记录在sys.modules中,因此,当导入一个模块时,python会先到sys.modules中查找,如果可以找到,那么直接提取对应的模块,如果找不到,则继续下一步查找。
sys.meta_path
接下来,python会直接按照sys.meta_path中各个查找器的顺序去查找模块,sys.meta_path是一个包含了几个模块查找器的列表,默认情况下,sys.meta_path中具有如下的查找器,以及查找顺序:
[<class '_frozen_importlib.BuiltinImporter'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib_external.PathFinder'>]
可以看到,第一个查找器时内置模块查找器,即python如果没有在sys.modules中找到相应模块,则会进一步查找内置模块中是否有想要被导入的模块。如果内置模块中没有找到,会进一步查找frozen模块,如果还是没有找到,则再通过PathFinder去查找。这里最后一个PathFinder实际上就是通过sys.path中的路径逐个查找的,如果还是没有找到,则最终会报出异常。
sys.meta_path是一个可以改变的列表,如果我们在导入模块之前,改变这个列表的内容,都会影响python对模块的查找,比如调换顺序则会影响python对模块的查找顺序,或者直接清空该列表,那么python除了sys.modules缓存的模块外,不能成功导入任何模块。
内置模块指的是用c编写的关键组件模块,可以通过sys.builtin_module_names查看有哪些内置模块;frozen模块则是用python编写,但是通过python的freeze工具编译后同python解释器一同发布的模块,这种模块可以直接再unix系统上运行,就跟c的二进制程序一样。
如果我们想知道某个模块的详细信息,可以通过importlib.util.find_spec(m)函数获取模块m的信息,可以查看其到底时什么模块。
sys.path
可以看到,在进入sys.path中的路径查找之前,python对于模块查找会先经历sys.modules缓存查找、内置模块查找和frozen模块查找三个环节,只有上面三个都没有找到,才会进入sys.path路径查找。
sys.path中主要依次包含三类路径:直接主脚本所在的目录或者进行交互python环境所在的工作目录、PYTHONPATH路径和包默认的安装路径(如site-package)。
相对导入
除了绝对导入外,python中还可以进行包内的相对导入,用点号开头表示,比如from . import xxx、from .. import xxx、from .A import xxx、from ..A import xxx等都是相对导入,相对导入有两个语法特点:1、 一定时以from开头导入;2、from后跟的名称一定是以点号开头,表示相对路径。
相对导入是通过当前模块的名称__name__来定位被导入模块位置的。假设包A的结构如下所示,在test.py中有from .. import t0,t1的__name__属性为A.B.t1,一个点号表示A.B,两个点号表示A,python会通过t1的__name__属性来定位其所在的位置,以及查找被导入模块的位置。
A/__init__.pyt0.pyB/__init__.pytest.pyt1.py
那么,当执行from .. import t0时,python背后到底做了什么?首先,跟绝对导入一样,python会在模块缓存sys.modules中查找是否已经有A,如果没有,则会先导入A,进一步检查是否有A.t0,如果有就直接引用,如果没有,python会先从A的命名空间中查找,A的命名空间就是A下面的__init__.py脚本执行后,里面所创建的对象,如果没有在A的命名空间中找到,则会在A对应目录下查找,如果还是没有找到,则会报出异常。所以,对于相对导入,在真正查找到物理模块前,会先经历sys.modules缓存模块查找和包模块的初始化文件创建的命名空间查找。
__init__.py相对导入
__init__.py初始化文件中的相对导入和常规相对导入是一样的,这里之所以特地拿出来强调,是因为在目录查找之前,还会经历__init__.py的命名空间查找,所以如果所在相应的包目录下并不存在想要被导入的模块,但是在__init__.py中定义了相应的被导入对象的话,那么导入语句依然会成功运行,会导入__init__.py中定义的对象。
mian脚本中的相对导入
windows系统下,python3在main脚本中不允许相对导入。
在unix系统下,通常相对导入语法只会在包内发生,但是有一个特例,那就是在__name__属性为__main__的主脚本中也允许相对导入语法。当在主脚本中运行相对导入时,主脚本就相当于包的顶层目录下的__init__.py,只允许一个点号,即from . import x,因为如果超过一个点号就会报超出顶层包目录的异常,而且,这里的x也只有在主脚本里面在导入语句之前被定义的情况下,该相对导入语句才会成功运行。
Reference
1. 5. The import system — Python 3.10.4 documentation
2. Python Cookbook, Third Edition: Beazley, David, Jones, Brian
3. PEP 328 – Imports: Multi-Line and Absolute/Relative | peps.python.org
python模块导入详解相关推荐
- python怎么导入文件-Python模块导入详解
定义 模块:用来从逻辑上组织Python代码(变量.函数.类.逻辑)去实现一个功能.本质就是.py结尾的Python文件. 包:用来从逻辑上组织模块的(可以放一堆模块在目录下).本质就是一个目录(必须 ...
- python怎么导入视频-Python模块导入详解
定义 模块:用来从逻辑上组织Python代码(变量.函数.类.逻辑)去实现一个功能.本质就是.py结尾的Python文件. 包:用来从逻辑上组织模块的(可以放一堆模块在目录下).本质就是一个目录(必须 ...
- python模块导入_Python模块导入详解
定义 模块:用来从逻辑上组织Python代码(变量.函数.类.逻辑)去实现一个功能.本质就是.py结尾的Python文件. 包:用来从逻辑上组织模块的(可以放一堆模块在目录下).本质就是一个目录(必须 ...
- python导入模块语句_python 模块导入详解
本文不讨论 Python 的导入机制(底层实现细节),仅讨论模块与包,以及导入语句相关的概念.通常,导入模块都是使用如下语句: import...import... as ...from ... im ...
- Python模块(Module)详解
文章目录 一.模块概念 二.模块导入与使用 2.0 准备工作 2.1 import 2.1.1 导入 2.1.2 使用 2.2 from...import 2.2.1 导入 2.2.2 使用 2.3 ...
- python包导入详解
内容介绍 本文重点在总结python脚本在导入包的流程.方便后期项目中环境搭建,部署,包封装问题处理. 基本语法 import 包名 import 包名.模块名 from 包名 import 模块名 ...
- python标准库对象导入语句_Python标准库之Sys模块使用详解
sys 模块提供了许多函数和变量来处理 Python 运行时环境的不同部分. 处理命令行参数 在解释器启动后, argv 列表包含了传递给脚本的所有参数, 列表的第一个元素为脚本自身的名称. 使用sy ...
- python导入模块介绍_详解Python模块导入方法
python常被昵称为胶水语言,它能很轻松的把用其他语言制作的各种模块(尤其是C/C++)轻松联结在一起.python包含子目录中的模块方法比较简单,关键是能够在sys.path里面找到通向模块文件的 ...
- python发邮件详解 -- smtplib和email模块
文章目录 python发邮件详解,-->smtplib和email模块 1.python发邮件所需要的基础包 2.smtplib的用法 3.email模块的详细理解和使用 A.MIMEText对 ...
- python中docx模块的使用_python使用docx模块读写docx文件的方法与docx模块常用方法详解...
一,docx模块 Python可以利用python-docx模块处理word文档,处理方式是面向对象的.也就是说python-docx模块会把word文档,文档中的段落.文本.字体等都看做对象,对对象 ...
最新文章
- java不同的数据源如何处理_java – 如何在不同的数据源上创建两个类之间的关系?...
- 末日来临,你的编程语言能干嘛? | 每日趣闻
- 在spring MVC项目中集成Spring session redis (使用spring session框架,redis作为存储缓存)...
- esp分区引导修复失败_Windows10修复UEFI引导的具体方法
- 【前端】网页布局基础
- 专题2-通过按键玩中断\第1课-中断处理流程深度剖析-lesson1
- android 扫描照片功能,Android自定义View- 雷达扫描图
- 列名 userid 不明确。 表结构_那些你不知道的表结构设计思路
- 英特尔核芯显卡控制面板没有了_核显和独显、集成显卡有什么区别
- Java—一篇读懂java集合(Collection/Map)及Lambda表达式
- 福特在迈阿密开始探索自动驾驶商业模式:先送比萨试试
- 蓝桥杯矩阵求和_刷蓝桥杯官网习题,准备蓝桥杯的小伙伴,一起来交流吧(✪ω✪)。(2月27日更新)...
- 卷积神经网络通俗易懂理解
- 计算机科学也有民科!看知乎计算机民科辩论大战!
- 不要让采购欺诈吃掉你的利润
- (译)在cocos2d里面如何使用物理引擎box2d:弹球
- 计算机无法开机如何读u盘启动,无法开机u盘装系统教程
- HTML、CSS学习总结
- 2016年,网络程序设计,ustc se,SA16225161,梁昱森
- 【原理/Java并发】从volatile到MESI协议