python中模块是单个.py文件,包是含__init__.py的目录;import涉及查找、编译、执行、缓存全过程,并将模块对象绑定到命名空间。

Python 中的模块(module)和包(package)本质都是用于组织代码的单位,区别关键在于有没有 __init__.py 文件以及能否被 Python 识别为命名空间容器。而 import 机制是 Python 加载并执行这些单位的核心流程,它不只“导入名字”,更涉及查找、编译、执行、缓存全过程。
模块:单个 .py 文件就是最简模块
一个以 .py 结尾的文件(如 utils.py)就是一个模块。导入时,Python 会:
- 在
sys.path列表中按顺序查找该文件(包括当前目录、site-packages、PYTHONPATH 等) - 找到后编译为字节码(
.pyc),缓存在__pycache__目录下(除非禁用) - 执行文件顶层代码(即缩进为 0 的语句),把所有定义(函数、类、变量)注入该模块的命名空间
- 将模块对象绑定到当前作用域(如
import utils→utils变量指向该模块对象)
包:带 __init__.py 的目录才是包
一个包含 __init__.py 文件的目录(哪怕该文件为空)会被 Python 视为包。例如:
myproject/
├── __init__.py
├── core.py
└── helpers/
├── __init__.py
└── string.py
这时 myproject 和 myproject.helpers 都是包。关键点:
立即学习“Python免费学习笔记(深入)”;
-
__init__.py会在包首次被导入时自动执行,常用于设置包级变量、触发子模块导入(如from . import core)、定义__all__ - 子模块路径用点号分隔:
import myproject.helpers.string或from myproject.helpers import string - 相对导入只在包内有效(如
from . import core),且必须在模块作为包的一部分运行时才合法(不能直接运行python helpers/string.py)
import 实际发生了什么?不只是“引入名字”
执行 import A 或 from A import B 时,Python 内部调用的是 __import__() 函数(不建议手动调用),整个过程包含:
-
查找阶段:通过
sys.meta_path中的查找器(finder)尝试定位模块/包。内置查找器支持.py、.pyc、C 扩展、命名空间包等 -
加载阶段:由加载器(loader)读取源码、编译、执行。包的加载会先执行其
__init__.py -
缓存机制:成功导入的模块会被存入
sys.modules字典。后续相同 import 不再重复查找和执行,直接复用已加载的模块对象 -
命名绑定:
import A把模块对象赋给局部名A;from A import B是从模块A的命名空间中取出B绑定到当前作用域(注意:不是引用,而是新绑定)
常见误区与实用提示
理解 import 行为能避免很多“找不到模块”或“修改不生效”的问题:
- 修改已导入模块的源码后,
import不会自动重载——需用importlib.reload(module)(仅限开发调试) -
from module import x后再import module; module.x = ...,不会影响已导入的x,因为它是独立对象引用 - 循环导入不一定报错,但可能因模块未完全初始化导致属性缺失(如 A 导入 B,B 又在顶层导入 A,此时 A 的部分代码还没执行完)
- 想让包支持
from package import *,需在__init__.py中定义__all__ = ['func1', 'ClassA']










