| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Python知识库 -> python模块导入详解 -> 正文阅读 |
|
[Python知识库]python模块导入详解 |
目录 包和模块????????我们可以在一个脚本中定义变量、函数和类,并添加逻辑,但是当某个项目具有复杂的逻辑时,我们希望把这些逻辑分解成不同的脚本,并以一定的合理的方式组织成层级结构,这种具有层级结构的包含脚本的文件夹就称为包。 ????????模块通常指的是定义了变量、函数和类的脚本。但是实际上,包也属于模块的一种,区分一个模块到底是包还是某个具体的脚本,就看该模块是否具有__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中具有如下的查找器,以及查找顺序:
? ? ? ? 可以看到,第一个查找器时内置模块查找器,即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__属性来定位其所在的位置,以及查找被导入模块的位置。
? ? ? ? 那么,当执行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脚本中的相对导入? ? ? ? 通常相对导入语法只会在包内发生,但是有一个特例,那就是在__name__属性为__main__的主脚本中也允许相对导入语法。当在主脚本中运行相对导入时,主脚本就相当于包的顶层目录下的__init__.py,只允许一个点号,即from . import x,因为如果超过一个点号就会报超出顶层包目录的异常,而且,这里的x也只有在主脚本里面在导入语句之前被定义的情况下,该相对导入语句才会成功运行。 Reference1.?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 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 15:58:01- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |