模块与包 (Modules and Packages)
随着代码量的增加,将所有代码写在一个文件中会变得难以维护。Python 提供了模块 (Module) 和 包 (Package) 的机制,帮助我们要组织和管理代码结构。
1. 什么是模块?
简单来说,一个 .py 文件就是一个模块。模块中可以包含函数、类和变量。
假设我们有一个文件 my_math.py:
# my_math.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
PI = 3.14159
导入模块
我们可以使用 import 语句在其他文件中使用这个模块。
import my_math
print(my_math.add(1, 2))
print(my_math.PI)
导入特定成员
使用 from ... import ... 可以只导入需要的部分,这样可以直接使用函数名而不需要模块名前缀。
from my_math import add, PI
print(add(1, 2))
print(PI)
给模块起别名
使用 as 关键字可以给长模块名起个简短的别名。
import my_math as mm
print(mm.add(1, 2))
2. if __name__ == "__main__":
这是一个非常常见的惯用写法。
- 当模块被直接运行时,
__name__的值为"__main__"。 - 当模块被导入时,
__name__的值为模块的名字(如"my_math")。
这允许我们在模块中包含一些测试代码,这些代码只在直接运行模块时执行,而被导入到其他程序时不会执行。
# my_math.py
def add(a, b):
return a + b
if __name__ == "__main__":
print("Running as main program")
print("Testing add function:", add(1, 1))
3. 什么是包?
包 (Package) 是一个包含多个模块的目录。在 Python 3.3 之前,目录下必须包含一个 __init__.py 文件才能被视为包(虽然现在不是必须的,但保留它仍是一个好习惯,用于标识包被初始化时的逻辑)。
假设有如下目录结构:
my_project/
main.py
utils/
__init__.py
string_utils.py
file_utils.py
我们可以这样导入:
# main.py
from utils import string_utils
# 或者
from utils.string_utils import to_upper
__init__.py 的作用
__init__.py 可以为空,也可以包含包的初始化代码,或者通过 __all__ 变量控制 from package import * 时导出的模块。
# utils/__init__.py
print("Initializing utils package...")
# 可以在这里预先导入子模块,方便外部调用
from .string_utils import to_upper
这样外部就可以直接 from utils import to_upper 了。
4. 绝对导入 vs 相对导入
- 绝对导入:从项目根目录开始导入,如
from utils.string_utils import ...。(推荐) - 相对导入:使用
.表示当前目录,..表示上级目录,如from . import string_utils。(通常用于包内部模块之间的互相引用)
5. 标准库与第三方库
- 标准库:Python 自带的库,直接导入即可,如
os,sys,math,datetime,json等。 - 第三方库:需要通过
pip install安装的库,如requests,numpy,pandas等。
总结
- 模块就是一个
.py文件,包是一个包含模块的目录。 - 使用
import或from ... import导入代码。 - 利用
if __name__ == "__main__":区分脚本运行和模块导入。 - 合理的模块化设计能让代码结构清晰、易于复用和维护。
下一步
现在我们已经学会了如何组织代码,接下来我们将学习如何处理更复杂的数据交换和文件操作,比如 JSON 序列化、CSV 处理以及更优雅的路径操作库 pathlib。