目录

包和模块

模块导入

绝对导入

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模块导入详解相关推荐

  1. python怎么导入文件-Python模块导入详解

    定义 模块:用来从逻辑上组织Python代码(变量.函数.类.逻辑)去实现一个功能.本质就是.py结尾的Python文件. 包:用来从逻辑上组织模块的(可以放一堆模块在目录下).本质就是一个目录(必须 ...

  2. python怎么导入视频-Python模块导入详解

    定义 模块:用来从逻辑上组织Python代码(变量.函数.类.逻辑)去实现一个功能.本质就是.py结尾的Python文件. 包:用来从逻辑上组织模块的(可以放一堆模块在目录下).本质就是一个目录(必须 ...

  3. python模块导入_Python模块导入详解

    定义 模块:用来从逻辑上组织Python代码(变量.函数.类.逻辑)去实现一个功能.本质就是.py结尾的Python文件. 包:用来从逻辑上组织模块的(可以放一堆模块在目录下).本质就是一个目录(必须 ...

  4. python导入模块语句_python 模块导入详解

    本文不讨论 Python 的导入机制(底层实现细节),仅讨论模块与包,以及导入语句相关的概念.通常,导入模块都是使用如下语句: import...import... as ...from ... im ...

  5. 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 ...

  6. python包导入详解

    内容介绍 本文重点在总结python脚本在导入包的流程.方便后期项目中环境搭建,部署,包封装问题处理. 基本语法 import 包名 import 包名.模块名 from 包名 import 模块名 ...

  7. python标准库对象导入语句_Python标准库之Sys模块使用详解

    sys 模块提供了许多函数和变量来处理 Python 运行时环境的不同部分. 处理命令行参数 在解释器启动后, argv 列表包含了传递给脚本的所有参数, 列表的第一个元素为脚本自身的名称. 使用sy ...

  8. python导入模块介绍_详解Python模块导入方法

    python常被昵称为胶水语言,它能很轻松的把用其他语言制作的各种模块(尤其是C/C++)轻松联结在一起.python包含子目录中的模块方法比较简单,关键是能够在sys.path里面找到通向模块文件的 ...

  9. python发邮件详解 -- smtplib和email模块

    文章目录 python发邮件详解,-->smtplib和email模块 1.python发邮件所需要的基础包 2.smtplib的用法 3.email模块的详细理解和使用 A.MIMEText对 ...

  10. python中docx模块的使用_python使用docx模块读写docx文件的方法与docx模块常用方法详解...

    一,docx模块 Python可以利用python-docx模块处理word文档,处理方式是面向对象的.也就是说python-docx模块会把word文档,文档中的段落.文本.字体等都看做对象,对对象 ...

最新文章

  1. java不同的数据源如何处理_java – 如何在不同的数据源上创建两个类之间的关系?...
  2. 末日来临,你的编程语言能干嘛? | 每日趣闻
  3. 在spring MVC项目中集成Spring session redis (使用spring session框架,redis作为存储缓存)...
  4. esp分区引导修复失败_Windows10修复UEFI引导的具体方法
  5. 【前端】网页布局基础
  6. 专题2-通过按键玩中断\第1课-中断处理流程深度剖析-lesson1
  7. android 扫描照片功能,Android自定义View- 雷达扫描图
  8. 列名 userid 不明确。 表结构_那些你不知道的表结构设计思路
  9. 英特尔核芯显卡控制面板没有了_核显和独显、集成显卡有什么区别
  10. Java—一篇读懂java集合(Collection/Map)及Lambda表达式
  11. 福特在迈阿密开始探索自动驾驶商业模式:先送比萨试试
  12. 蓝桥杯矩阵求和_刷蓝桥杯官网习题,准备蓝桥杯的小伙伴,一起来交流吧(✪ω✪)。(2月27日更新)...
  13. 卷积神经网络通俗易懂理解
  14. 计算机科学也有民科!看知乎计算机民科辩论大战!
  15. 不要让采购欺诈吃掉你的利润
  16. (译)在cocos2d里面如何使用物理引擎box2d:弹球
  17. 计算机无法开机如何读u盘启动,无法开机u盘装系统教程
  18. HTML、CSS学习总结
  19. 2016年,网络程序设计,ustc se,SA16225161,梁昱森
  20. 【原理/Java并发】从volatile到MESI协议

热门文章

  1. 从事大数据行业5年,峰哥总结出了以下 7 条建议
  2. RxJava2+retrofit实现网络封装
  3. ajax请求接口连不上会报错吗_本地ajax请求服务器
  4. MATLAB中将数字转换成罗马数字
  5. 你应当知道的人工智能发展历史
  6. 人员招聘与培训实务【1】
  7. MacOS 访达 查看隐藏文件隐藏文件夹
  8. 基于Python将图片转换成素描图片
  9. 【软著】自己申请软件著作权流程
  10. ORA-20011KUP-11024ORA-29913