Python 模块与包详解:import 背后的原理

小飞兽 Python 127 次阅读 2026-07-14

引言

Python 能成为全球最流行的编程语言之一,"模块与包"机制功不可没。它让代码复用变得极其简单——安装一个第三方包只需要一行 pip install xxx,这背后的原理就是 Python 模块系统。

一、模块到底是什么

概念

模块(Module)就是一个 .py 文件。文件名就是模块名,文件里的函数、类、变量都可以被其他文件导入使用。

第一个模块

创建 greet.py

# greet.py
def say_hello(name):
    return f"你好,{name}!"

VERSION = "1.0.0"

在另一个文件里使用它:

# main.py
import greet

print(greet.say_hello("小飞兽"))  # 输出:你好,小飞兽!
print(greet.VERSION)               # 输出:1.0.0

这就是模块的基本用法。

导入的多种方式

# 方式一:导入整个模块(最常用)
import math
print(math.sqrt(16))  # 4.0

# 方式二:给模块起别名
import math as m
print(m.sqrt(16))

# 方式三:只导入需要的内容(推荐写法)
from math import sqrt
print(sqrt(16))

# 方式四:从模块导入所有内容(不推荐,可能命名冲突)
from math import *
print(sqrt(16))

# 方式五:从模块导入并起别名
from math import sqrt as s
print(s(16))

二、<code>__name__</code> 特殊变量

每个 .py 文件都有一个隐藏的 __name__ 变量:

# greet.py
def hello():
    print("Hello!")

if __name__ == "__main__":
    # 只有直接运行这个文件时才执行
    hello()
    print("直接运行 greet.py")

当运行 python greet.py 时,__name__ 的值是 "__main__",所以 if 里的代码会执行。

当在其他文件 import greet 时,__name__ 的值是 "greet"if 里的代码不会执行。

这个机制常用于:让模块既能直接运行测试,又能被其他文件导入使用。

三、包(Package)

包的概念

是包含 __init__.py 文件的目录,目录里可以放多个模块。

mypackage/
├── __init__.py        # 包初始化文件
├── utils.py           # 模块1
├── api.py             # 模块2
└── db/
    ├── __init__.py
    └── connection.py  # 子包

创建和使用包

# mypackage/utils.py
def add(a, b):
    return a + b

def multiply(a, b):
    return a * b
# mypackage/__init__.py
# 可以在这里指定默认导出
from .utils import add, multiply
__all__ = ['add', 'multiply']
# main.py
import mypackage

print(mypackage.add(2, 3))       # 5
print(mypackage.multiply(2, 3))  # 6

<code>__init__.py</code> 的作用

__init__.py 在包被首次 import 时自动执行。它的常见用途:

1. 设置包级别的导入from .module import stuff
2. 初始化配置:设置包的状态
3. 控制 <code>from package import *</code> 的行为__all__ = ['func1', 'func2']

相对导入与绝对导入

# 假设在 mypackage/utils.py 中

# 绝对导入(推荐)
from mypackage import db

# 相对导入(只在包内部使用)
from . import db          # 当前包下的 db 模块
from .db import connect   # 当前包下 db 子包的 connect
from .. import other      # 上级包

四、Python 的模块搜索路径

当你执行 import xxx 时,Python 按以下顺序查找模块:

import sys
print(sys.path)

输出类似:

['/path/to/current/script',
 '/usr/lib/python3.12',
 '/usr/lib/python3.12/lib-dynload',
 '/usr/lib/python3.12/site-packages',
 '/home/user/.local/lib/python3.12/site-packages']

搜索顺序:
1. 当前脚本所在目录
2. PYTHONPATH 环境变量指定的目录
3. Python 安装目录的 lib
4. 第三方包目录 site-packages

动态添加搜索路径

import sys
sys.path.insert(0, '/path/to/your/module')

import mymodule  # 现在可以导入 /path/to/your/module/mymodule.py 了

五、常用标准库模块

Python 自带大量标准库,无需额外安装:

# 文件和目录操作
import os
print(os.getcwd())           # 当前工作目录
os.listdir('.')              # 列出当前目录文件
os.makedirs('new_folder', exist_ok=True)  # 创建目录

# 路径处理
import pathlib
p = pathlib.Path('/home/user/doc.txt')
print(p.parent)   # /home/user
print(p.stem)     # doc
print(p.suffix)   # .txt

# 日期和时间
from datetime import datetime, timedelta
now = datetime.now()
print(now.strftime('%Y-%m-%d %H:%M:%S'))
future = now + timedelta(days=7)
print(future)

# JSON 处理
import json
data = {'name': '小飞兽', 'age': 25}
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)  # {"name": "小飞兽", "age": 25}
parsed = json.loads(json_str)

# 正则表达式
import re
text = "我的邮箱是 test@example.com"
match = re.search(r'[\w.-]+@[\w.-]+', text)
print(match.group())  # test@example.com

# 随机数
import random
print(random.randint(1, 100))  # 1-100随机整数
print(random.choice(['苹果', '香蕉', '橙子']))  # 随机选一个

# 集合与计数器
from collections import Counter
cnt = Counter(['苹果', '香蕉', '苹果', '橙子', '苹果'])
print(cnt.most_common(2))  # [('苹果', 3), ('香蕉', 1)]

六、第三方包管理

pip 基础命令

# 安装包
pip install requests

# 安装指定版本
pip install numpy==1.24.0

# 升级包
pip install --upgrade pandas

# 卸载包
pip uninstall numpy

# 列出已安装的包
pip list

# 导出依赖列表
pip freeze > requirements.txt

# 从文件安装
pip install -r requirements.txt

虚拟环境(重要)

建议每个项目使用独立虚拟环境,避免版本冲突:

# 创建虚拟环境
python -m venv myenv

# 激活虚拟环境
# Linux/Mac:
source myenv/bin/activate
# Windows:
myenv\Scripts\activate

# 激活后安装的包只在这个环境里
pip install flask

# 退出虚拟环境
deactivate

七、常见问题

Q1:<code>ImportError: No module named xxx</code>

分情况排查:

# 1. 确认包是否安装
pip list | grep xxx

# 2. 确认 Python 版本
python --version  # 可能是 python3 而不是 python

# 3. 确认 pip 对应正确的 Python 版本
python -m pip install xxx

Q2:<code>ModuleNotFoundError</code> 和 <code>ImportError</code> 区别?

  • <code>ModuleNotFoundError</code>:找不到模块文件(文件不存在或路径错误)

  • <code>ImportError</code>:找到了模块但导入失败(可能是模块里代码报错,或者缺少依赖)

Q3:循环导入(circular import)怎么办?

# a.py
import b
def func_a():
    return b.func_b()

# b.py
# 不要在这里直接 import a,可以:
def func_b():
    from a import func_a  # 在函数内部导入
    return func_a()

Q4:如何查看模块的源代码位置?

import requests
print(requests.__file__)
# 输出:/usr/lib/python3.12/site-packages/requests/__init__.py

八、总结

模块与包是 Python 代码组织的核心:

| 概念 | 定义 | 标识 |
|------|------|------|
| 模块 | 单个 .py 文件 | import xxx |
| 包 | 含 __init__.py 的目录 | import package.module |
| __name__ | 当前文件名称 | "__main__" 表示直接运行 |
| __init__.py | 包初始化文件 | 包首次导入时自动执行 |
| __all__ | 导出列表 | 控制 from package import * 的行为 |

记住:一切皆模块。Python 的强大生态建立在模块系统之上,学会模块管理,就掌握了 Python 开发的钥匙。