案例目录
├─📁 modules/
│ ├─📄 __init__.py
│ ├─📄 example.py
├─📄 modules.py
├─📄 main.py
├─📄 mymath.py
导入module
import mymath实际上import的过程有以下步骤:
- 生成一个module类型的实例(并运行),并将其赋值给相应的变量mymath使其得以被使用
- 如果实例已经存在,则刷新缓存
module就是模块引入main.py后全局的命名空间
import mymath as mm,此时此时import的过程有以下步骤:
- 生成一个module类型的实例(并运行),并将其赋值给相应的变量mm使其得以被使用(无mymath这个命名空间)
- 如果实例已经存在,则刷新缓存,并将其赋值给新的变量(不再运行)。新旧变量ID相同,即指向同一个module对象
from mymath import PI,此时import的过程有以下步骤:
- 生成一个module类型的实例(并运行),但不将其赋值给mymath,而是将PI的值直接赋值给当前空间的PI变量
对于数值变量来说,import完成之后mymath.py中的PI则与当前空间main.py中的PI没有关系了(互相不再影响)
因此import的本质就是创建命名空间,然后对当前空间的变量进行赋值的过程
module:代码从哪里找
多层级的寻找顺序:Builtin module(自带)-执行目录下查找--lib库下查找--sys.path下查找
从sys.path中找,它是一个list,记录着寻找代码的目标路径。其中如下(个人见解:类似于嵌入式python包中.pth后缀的文件)
‘./import’, # import指向的目录
'/usr/lib/python310.zip',
'/usr/lib/python3.10',
'/usr/lib/python3.10/lib-dynload', # python包自身文件
'/xxxxxxx/lib/python3.10/site-packages', # 安装的第三方包目录
其可以通过代码进行修改,也可以在运行python时指定环境变量PYTHONPATH来改变,如
PYTHONPATH=/a/b/c/ python main.py
导入package
如案例目录中import modules会执行如下步骤:
- 生成一个package类型的实例(并运行__init__.py,如有),即在当前命名空间中创建一个modules命名空间
- 此时package中的其他文件并不会被导入
package就是包引入main.py后全局的命名空间,是一种特殊的module
可以导入子文件module或子目录subpackage,如import modules.example,执行如下步骤:
- 在当前命名空间中创建一个modules命名空间,如已存在则更新缓存
- 在modules的命名空间中创建一个example命名空间
或from modules import example,会执行如下步骤:
- 在当前命名空间中创建一个modules命名空间,如已存在则更新缓存
- 在当前命名空间中创建一个example命名空间
- 在modules的命名空间中创建一个example命名空间
Relative import
from . import *、from .modules import example、from .. import mymath等
原理:python运行时先通过__package__识别该文件属于哪个package,替换.,即需转换为绝对路径后再执行
影响:写了相对导入的module无法直接运行并通过 if name == "main" 来进行测试
建议不使用relative import!
确保模块能正确import
在文件添加以下内容
import sys
sys.path.append(root_path) # root_path为项目路径