当前位置:首页>python>【一起学Python】第21天:函数与模块化的使用

【一起学Python】第21天:函数与模块化的使用

  • 2026-10-01 12:28:28
【一起学Python】第21天:函数与模块化的使用

在掌握了函数(Function)的基础上,随着代码量的增加,我们需要更好的组织方式。模块化(Modularization) 是将大型程序分解为小型、可管理部分的核心思想。

如果把 函数 比作“砖块”,那么 模块(Module) 就是“墙壁”,包(Package) 就是“房间”。


一、为什么需要模块化?

当代码超过几百行时,单个文件会变得难以维护。模块化带来的好处:

  1. 代码复用:写好的功能可以在不同项目中直接引用。
  2. 命名空间管理:避免变量名冲突(如 utils.calculate vs math.calculate)。
  3. 团队协作:不同开发者负责不同的模块。
  4. 易于测试:可以单独测试某个模块的功能。

二、模块(Module)基础

1. 什么是模块?

在 Python 中,一个 .py 文件就是一个模块。

2. 创建模块

新建一个文件 mymath.py:

# mymath.pydef add(a, b):    return a + bdef sub(a, b):    return a - bPI = 3.14159

3. 导入模块

在其他文件中使用 import 关键字。

# main.pyimport mymathprint(mymath.add(1, 2))  # 3print(mymath.PI)         # 3.14159

4. 多种导入方式

方式

代码示例

说明

整体导入

import mymath

使用时需加前缀 mymath.func()

部分导入

from mymath import add

直接使用 add()

全部导入

from mymath import *

导入所有公开内容(不推荐)

别名导入

import mymath as mm

使用简称 mm.func()

三、包(Package)基础

1. 什么是包?

包是一个包含 __init__.py 文件的目录。它用于组织多个模块。

2. 目录结构示例

my_project/│├── main.py└── utils/              <-- 包    ├── __init__.py     <-- 标志这是一个包    ├── string_utils.py <-- 模块    └── math_utils.py   <-- 模块

3. __init__.py 的作用

  • 标识目录为包。
  • 可以初始化包级别的变量。
  • 控制 from utils import * 导入的内容(通过 __all__)。

4. 导入包中的模块

# main.pyfrom utils import string_utilsfrom utils.math_utils import addprint(string_utils.upper_case("hello"))print(add(1, 2))

四、关键机制详解

1. if __name__ == '__main__':

这是模块化编程最重要的习惯。它确保代码块只在直接运行该文件时执行,而在被导入时不执行。

# test.pydef func():    print("函数被调用")print("模块被加载")if __name__ == '__main__':    print("主程序运行")    func()
  • 直接运行 python test.py:输出全部三行。
  • 被导入 import test:只输出“模块被加载”。

2. 模块搜索路径 (sys.path)

Python 导入模块时,会按顺序查找以下路径:

  1. 当前脚本所在目录。
  2. 环境变量 PYTHONPATH 中的目录。
  3. 标准库目录。
  4. 第三方库目录 (site-packages)。
import sysprint(sys.path)  # 查看搜索路径

3. 相对导入 vs 绝对导入

在包内部导入时:

  • 绝对导入:from utils.math_utils import add
  • 相对导入:from .math_utils import add(. 代表当前包,.. 代表上一级)

⚠️ 注意:相对导入通常在包内部使用,主程序入口建议使用绝对导入。

五、标准库常用模块

Python 自带丰富的“电池 Included"标准库,无需安装即可使用。

模块

功能

示例

os

操作系统接口

os.getcwd(), os.mkdir()

sys

系统相关参数

sys.argv, sys.path

datetime

日期时间处理

datetime.now()

json

JSON 数据解析

json.loads(), json.dump()

math

数学运算

math.sqrt(), math.pi

random

随机数生成

random.randint(), random.choice()

示例:使用 json 和 datetime

import jsonfrom datetime import datetimedata = {"name": "Alice", "time": str(datetime.now())}# 序列化json_str = json.dumps(data, ensure_ascii=False)print(json_str)# 反序列化obj = json.loads(json_str)print(obj["name"])

六、推荐的项目结构

对于中型项目,建议采用以下结构:

project_name/│├── src/                  # 源代码目录│   └── package_name/     # 主包│       ├── __init__.py│       ├── module1.py│       └── module2.py│├── tests/                # 测试代码│   ├── __init__.py│   └── test_module1.py│├── requirements.txt      # 依赖列表├── README.md             # 项目说明└── main.py               # 入口文件

为什么要这样分?

  • src 布局:避免导入冲突,明确区分源代码和测试代码。
  • requirements.txt:方便他人安装依赖 (pip install -r requirements.txt)。

七、实战案例:构建一个工具包

1. 创建目录结构

my_tools/├── __init__.py├── text.py└── number.py

2. 编写模块代码

# my_tools/text.pydef reverse(s):    return s[::-1]def capitalize(s):    return s.upper()
# my_tools/number.pydef is_even(n):    return n % 2 == 0
# my_tools/__init__.pyfrom .text import reverse, capitalizefrom .number import is_even__all__ = ['reverse', 'capitalize', 'is_even']

3. 使用工具包

# main.pyfrom my_tools import reverse, is_evenprint(reverse("hello"))  # ollehprint(is_even(4))        # True

八、常见陷阱与最佳实践

❌ 避免循环导入

A 导入 B,B 又导入 A,会导致错误。解决:重构代码,将公共部分提取到第三个模块 C,让 A 和 B 都导入 C。

❌ 避免 from module import *

这会污染命名空间,不知道哪些名字被导入。解决:明确导入需要的函数 from module import func。

✅ 使用虚拟环境

不同项目可能需要不同版本的库。

python -m venv venvsource venv/bin/activate  # Windows: venv\Scripts\activate

✅ 编写 docstring

每个模块和函数都应包含文档字符串,方便生成文档和 IDE 提示。

九、总结

概念

对应实体

关键文件/关键字

函数

代码块

def, return

模块

.py 文件

import, __name__

包

文件夹

__init__.py, . (相对导入)

依赖

第三方库

pip, requirements.txt

模块化是 Python 工程化的第一步。学会组织代码,比写出复杂的算法更重要!

最新文章

随机文章