模块
在 Python 中,一个 .py 文件就是一个模块,当你导入一个文件时,你实际上是在导入这个文件所定义的模块。

假设你有以下两个文件,它们都在同一个目录下:
my_module.py (要被导入的文件)
# 定义一个变量
MY_CONSTANT = "Hello from my_module!"
# 定义一个函数
def greet(name):
"""一个简单的问候函数"""
return f"Hello, {name}! Welcome to the module."
# 定义一个类
class Calculator:
"""一个简单的计算器类"""
def add(self, a, b):
return a + b
main.py (执行导入的文件)
# --- 导入方式演示 ---
# 方式一:导入整个模块
import my_module
# 使用模块名.成员名 的方式访问
print("--- 使用 'import my_module' ---")
print(my_module.MY_CONSTANT)
print(my_module.greet("Alice"))
calc = my_module.Calculator()
print(f"10 + 5 = {calc.add(10, 5)}")
print("\n" + "="*30 + "\n")
# 方式二:导入特定成员
from my_module import greet, MY_CONSTANT
# 直接使用成员名,无需模块名前缀
print("--- 使用 'from my_module import greet, MY_CONSTANT' ---")
print(MY_CONSTANT)
print(greet("Bob"))
# 注意:Calculator 类没有被导入,所以下面这行会报错
# calc = Calculator()
当你运行 main.py 时,输出将会是:

--- 使用 'import my_module' ---
Hello from my_module!
Hello, Alice! Welcome to the module.
10 + 5 = 15
==============================
--- 使用 'from my_module import greet, MY_CONSTANT' ---
Hello from my_module!
Hello, Bob!
详细的导入方法
import module_name
这是最基本、最推荐的方式,尤其是在大型项目中。
- 如何工作:它将整个
my_module.py文件加载到内存中,并将其作为一个名为my_module的命名空间。 - 如何访问:必须使用
模块名.成员名的格式来访问模块中的变量、函数和类。 - 优点:
- 命名空间清晰:可以清楚地知道一个函数或变量来自哪个模块,避免了命名冲突,如果另一个模块里也有一个
greet函数,使用my_module.greet()和other_module.greet()就能明确区分。 - 代码可读性强:代码的来源一目了然。
- 命名空间清晰:可以清楚地知道一个函数或变量来自哪个模块,避免了命名冲突,如果另一个模块里也有一个
- 缺点:
每次访问成员时都需要输入模块名,稍微繁琐一点。
from module_name import name1, name2, ...
这种方式可以导入模块中的一个或多个特定成员。
- 如何工作:它将指定的成员(如
greet,MY_CONSTANT)直接导入到当前文件的命名空间中。 - 如何访问:直接使用成员名,如
greet("Bob")。 - 优点:
- 代码简洁:无需每次都写模块名,对于频繁使用的成员非常方便。
- 缺点:
- 可能引发命名冲突:如果当前文件已经有一个同名的变量或函数,导入的成员会覆盖它。
- 可读性稍差:如果不看文件顶部的
import语句,可能不清楚greet函数是从哪里来的。
from module_name import *
这是一个强烈不推荐的用法,它会导入模块中除下划线 _ 开头之外的所有成员。

- 如何工作:将目标模块的所有公共成员全部导入到当前命名空间。
- 如何访问:直接使用成员名。
- 优点:无(除了在交互式解释器中快速测试)。
- 缺点:
- 严重污染命名空间:几乎肯定会导致命名冲突,尤其是在多个模块都使用
import *的情况下。 - 代码难以理解和维护:你无法一眼看出一个变量或函数的来源,调试起来非常痛苦。
- 破坏了显式优于隐式的 Python 哲学。
- 严重污染命名空间:几乎肯定会导致命名冲突,尤其是在多个模块都使用
import module_name as alias
为模块或成员提供一个简短的别名,这在处理长模块名或避免命名冲突时非常有用。
-
为整个模块设置别名:
import numpy as np # NumPy 库的常用别名 import pandas as pd # Pandas 库的常用别名 array = np.array([1, 2, 3]) data_frame = pd.DataFrame({'col1': [1, 2]}) -
为成员设置别名:
from my_module import greet as say_hello print(say_hello("Charlie")) # 输出: Hello, Charlie! Welcome to the module.
Python 的模块搜索路径
当你执行 import my_module 时,Python 会在以下位置按顺序查找 my_module.py 文件:
- 当前目录:Python 会在你运行脚本的当前目录下查找。
- PYTHONPATH 环境变量:这是一个环境变量,包含了一系列目录,Python 也会在这些目录中查找。
- 标准库路径:Python 安装目录下的
lib等文件夹,包含了所有内置的标准库模块(如os,sys,math)。 - 第三方库路径:通常是
site-packages目录,你通过pip安装的所有第三方库都在这里。
你可以通过 sys.path 列表来查看 Python 的所有搜索路径:
import sys print(sys.path)
这个列表是可修改的,如果你想让 Python 去一个特定的目录找模块,可以这样做:
import sys # 添加一个自定义路径到搜索列表的开头 sys.path.insert(0, '/path/to/your/modules')
注意:直接修改 sys.path 是一种快速但不太规范的方法,更专业的做法是使用虚拟环境(见下文)。
包
当你的项目变得很大时,模块也会越来越多,为了更好地组织模块,Python 引入了包的概念。
- 包:本质上是一个包含
__init__.py文件的目录,这个文件可以是一个空文件,它的作用是告诉 Python:“这个目录是一个包,可以被导入”。 - 子包:包内可以再包含子包,形成层级结构。
目录结构示例:
my_project/
├── main.py
├── my_package/
│ ├── __init__.py # 包的初始化文件
│ ├── module_a.py # 模块 A
│ ├── module_b.py # 模块 B
│ └── sub_package/
│ ├── __init__.py # 子包的初始化文件
│ └── module_c.py # 模块 C
如何导入包中的模块?
假设上面的目录结构,在 main.py 中:
-
导入包中的模块
# 从 my_package 包中导入 module_a from my_package import module_a module_a.some_function()
-
导入模块中的特定成员
# 从 my_package.sub_package 中导入 module_c 的一个函数 from my_package.sub_package.module_c import some_c_function some_c_function()
-
使用
import导入子包模块import my_package.sub_package.module_c as c_module c_module.some_c_function()
最佳实践与常见问题
使用虚拟环境
这是最重要的一点!当你开始一个新项目时,永远不要直接在系统 Python 环境中安装库,使用虚拟环境可以为每个项目创建一个隔离的、干净的 Python 环境。
-
为什么?
- 避免版本冲突:项目 A 需要
requests==2.25.0,而项目 B 需要requests==2.28.0,虚拟环境可以完美解决这个问题。 - 保持系统 Python 干净:不会把各种项目的库搞乱系统环境。
- 可复现性:可以轻松地创建一个包含所有依赖项的环境,方便部署和分享。
- 避免版本冲突:项目 A 需要
-
如何使用?
# 1. 创建虚拟环境 (venv 是 Python 内置的) python -m venv my_project_env # 2. 激活虚拟环境 # Windows: my_project_env\Scripts\activate # macOS / Linux: source my_project_env/bin/activate # 3. 现在你看到命令行前面会有 (my_project_env) 字样 # 安装库 pip install numpy pandas # 4. 退出虚拟环境 deactivate
在虚拟环境中,你只需要将你的项目根目录(包含 my_package 的目录)作为工作目录,Python 就能正确找到你的模块。
循环导入
这是模块导入中一个非常经典的错误。
场景:
module_a.py 依赖于 module_b.py,module_b.py 也依赖于 module_a.py。
# module_a.py
print("Module A is being imported...")
from module_b import my_function_b # 尝试导入 B 的函数
def my_function_a():
print("Function A is called")
my_function_b() # 调用 B 的函数
# module_b.py
print("Module B is being imported...")
from module_a import my_function_a # 尝试导入 A 的函数
def my_function_b():
print("Function B is called")
my_function_a() # 调用 A 的函数
# main.py
import module_a
运行 main.py 时,你会得到一个 ImportError,因为 Python 在加载 module_a 时,会尝试加载 module_b,而 module_b 又会尝试加载 module_a,形成一个死循环。
解决方案:
-
重构代码:这是最好的方法,尝试将两个模块相互依赖的代码提取到一个新的、共同的第三个模块中。
-
延迟导入:在一个函数内部进行导入,而不是在模块顶层。
# module_a.py def my_function_a(): # 在函数内部才导入 B from module_b import my_function_b print("Function A is called") my_function_b() # module_b.py def my_function_b(): # 在函数内部才导入 A from module_a import my_function_a print("Function B is called") my_function_a()这种方法可以打破循环,但可能会使代码逻辑变得不那么清晰,应谨慎使用。
| 导入方式 | 语法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 标准导入 | import module |
命名空间清晰,无冲突 | 代码稍长 | 强烈推荐,尤其是大型项目 |
| 特定导入 | from module import name |
代码简洁 | 可能引发命名冲突 | 频繁使用模块中的少量成员时 |
| 通配导入 | from module import * |
无 | 严重污染命名空间,不推荐 | 极少使用,仅在交互式解释器中快速测试 |
| 别名导入 | import module as alias |
避免冲突,代码简洁 | 可读性取决于别名 | 长模块名或库的惯用别名(如 np, pd) |
显式优于隐式,清晰优于简洁,在大多数情况下,优先使用 import module 或 from module import specific_name,并善用虚拟环境来管理你的项目依赖。
