Python教程20:模块基础

“分而治之,事半功倍。”

当代码越来越多时,把所有代码放在一个文件里会变得难以维护。模块(Module)就是Python的代码组织方式,让你可以把相关功能分门别类。今天我们学习如何创建和使用模块。

1. 什么是模块

定义

**模块(Module)**是一个包含Python代码的.py文件。每个Python文件都可以作为一个模块被其他文件导入使用。

为什么需要模块

  • 代码复用:写一次,到处用
  • 命名空间:避免变量名冲突
  • 代码组织:按功能分类,便于维护
  • 协作开发:不同人负责不同模块

简单示例

创建一个文件math_utils.py

 1# math_utils.py
 2"""数学工具模块"""
 3
 4PI = 3.14159
 5
 6def add(a, b):
 7    """加法"""
 8    return a + b
 9
10def circle_area(radius):
11    """计算圆面积"""
12    return PI * radius ** 2
13
14class Calculator:
15    """计算器类"""
16    def multiply(self, a, b):
17        return a * b

在另一个文件中使用:

1# main.py
2import math_utils  # 导入模块
3
4print(math_utils.PI)                    # 3.14159
5print(math_utils.add(3, 5))            # 8
6print(math_utils.circle_area(5))        # 78.53975
7
8calc = math_utils.Calculator()
9print(calc.multiply(4, 5))              # 20

模块的本质

  • 模块是一个命名空间(namespace)
  • 文件名(去掉.py)就是模块名
  • 通过模块名访问其中的变量、函数、类

2. 导入模块的方式

Python提供了多种导入方式,适应不同场景。

方式1:import模块名

1import math_utils
2
3# 使用:模块名.成员
4result = math_utils.add(1, 2)

优点

  • 清晰知道函数来自哪个模块
  • 避免命名冲突

缺点

  • 每次都要写模块名,稍显繁琐

方式2:from模块 import成员

1from math_utils import add, PI
2
3# 直接使用成员,不需要模块名
4result = add(1, 2)
5print(PI)

优点

  • 代码更简洁

缺点

  • 可能产生命名冲突
  • 不清楚成员来自哪个模块

方式3:import模块 as别名

1import math_utils as mu  # 给模块起别名
2
3result = mu.add(1, 2)

使用场景

  • 模块名太长时
  • 避免模块名冲突
  • 遵循社区惯例(如import numpy as np

方式4:from模块 import *(不推荐)

1from math_utils import *
2
3# 导入模块中所有公开成员
4result = add(1, 2)
5print(PI)

为什么不推荐

  • 导入了哪些成员不明确
  • 容易产生命名冲突
  • 降低代码可读性
  • 违反Python之禅:“Explicit is better than implicit”

唯一例外:在交互式环境(REPL)中快速试验时可以使用。

3. 模块的搜索路径

当你import一个模块时,Python会按以下顺序搜索:

  1. 当前目录:执行脚本所在的目录
  2. PYTHONPATH 环境变量:用户自定义的路径
  3. 标准库目录:Python安装目录下的lib
  4. site-packages:第三方库的安装目录

查看搜索路径:

1import sys
2
3# sys.path是一个列表,包含所有搜索路径
4for path in sys.path:
5    print(path)

sys模块

  • Python标准库之一
  • 提供与Python解释器交互的功能
  • sys.path存储模块搜索路径

添加自定义路径

如果模块不在搜索路径中,可以手动添加:

1import sys
2
3# 添加路径(临时,仅当前运行有效)
4sys.path.append('/path/to/your/modules')
5
6# 现在可以导入该路径下的模块了
7import my_module

注意

  • 这种方式只在当前Python进程有效
  • 重启后需要重新添加
  • 更好的方式是配置PYTHONPATH环境变量

4. 模块的执行

__name__变量

每个模块都有一个特殊变量__name__

  • 作为模块被导入时:__name__是模块名
  • 作为脚本直接运行时:__name__"__main__"
 1# my_module.py
 2def hello():
 3    print("Hello from module")
 4
 5# 这段代码只在直接运行时执行,被导入时不执行
 6if __name__ == "__main__":
 7    print("模块被直接运行")
 8    hello()
 9else:
10    print("模块被导入")

作为脚本运行

1$ python my_module.py
2模块被直接运行
3Hello from module

作为模块导入

1import my_module  # 输出:模块被导入
2my_module.hello()  # 输出:Hello from module

为什么需要这个机制

  • 模块既可以被导入,也可以独立运行测试
  • 导入时不会执行测试代码
  • 是Python模块的标准做法

5. 常用的标准库模块

Python自带了丰富的标准库,这些是最常用的:

math - 数学函数

1import math
2
3# math模块提供数学函数和常量
4# 来自Python标准库,无需安装
5print(math.pi)           # 3.141592653589793
6print(math.sqrt(16))     # 4.0(平方根)
7print(math.ceil(3.2))    # 4(向上取整)
8print(math.floor(3.8))   # 3(向下取整)

random - 随机数

1import random
2
3# random模块用于生成随机数
4# 常用于游戏、模拟、采样等场景
5print(random.random())        # 0.0到1.0的随机浮点数
6print(random.randint(1, 10))  # 1到10的随机整数
7print(random.choice(['a', 'b', 'c']))  # 随机选择一个元素

datetime - 日期时间

 1from datetime import datetime, timedelta
 2
 3# datetime模块处理日期和时间
 4# Python标准库,处理时间相关操作
 5now = datetime.now()
 6print(now)  # 2024-01-15 10:30:00.123456
 7
 8# 时间计算
 9tomorrow = now + timedelta(days=1)
10print(tomorrow)

os - 操作系统接口

1import os
2
3# os模块提供操作系统相关功能
4# 文件路径、目录操作、环境变量等
5print(os.getcwd())  # 当前工作目录
6print(os.listdir('.'))  # 列出当前目录文件

json - JSON处理

 1import json
 2
 3# json模块用于JSON数据的编码和解码
 4# JSON是Web开发中最常用的数据交换格式
 5data = {"name": "Alice", "age": 25}
 6json_str = json.dumps(data)  # Python对象 → JSON字符串
 7print(json_str)  # '{"name": "Alice", "age": 25}'
 8
 9parsed = json.loads(json_str)  # JSON字符串 → Python对象
10print(parsed["name"])  # Alice

6. 模块的最佳实践

1. 模块文档字符串

 1"""
 2这是模块的文档字符串。
 3
 4应该说明:
 5- 模块的用途
 6- 主要功能
 7- 使用示例
 8"""
 9
10def my_function():
11    """函数文档"""
12    pass

2. 使用__all__控制导出

 1# my_module.py
 2"""我的模块"""
 3
 4__all__ = ['public_func', 'PUBLIC_VAR']  # 指定公开接口
 5
 6def public_func():
 7    """公开函数"""
 8    pass
 9
10def _private_func():
11    """私有函数(以_开头)"""
12    pass
13
14PUBLIC_VAR = 10
15_PRIVATE_VAR = 20

使用时:

1from my_module import *
2
3# 只会导入__all__中列出的成员
4public_func()  # OK
5# _private_func()  # NameError

__all__的作用

  • 明确模块的公开接口
  • 控制from module import *的行为
  • 提示用户哪些是稳定的API

3. 私有成员约定

 1# 以单下划线开头表示"内部使用"
 2_internal_var = 10
 3
 4def _internal_function():
 5    """这是内部函数,不应被外部调用"""
 6    pass
 7
 8# 正常命名表示公开接口
 9public_var = 20
10
11def public_function():
12    """这是公开函数"""
13    pass

约定

  • 单下划线_:内部使用,但仍可访问
  • 双下划线__:名称改编(name mangling),类中使用
  • 这只是约定,Python不强制私有性

7. 重新加载模块

模块只在第一次导入时执行,再次导入会使用缓存:

1import my_module  # 第一次:执行模块代码
2import my_module  # 第二次:使用缓存,不重新执行

强制重新加载(开发调试时用):

1import importlib  # Python标准库,提供导入相关工具
2
3import my_module
4# 修改了my_module.py后
5importlib.reload(my_module)  # 重新加载

注意

  • 生产环境不要用reload
  • 重启Python更可靠
  • reload主要用于交互式开发

8. 小结

今天我们学习了模块的基础:

  • 定义:.py文件就是模块
  • 导入方式:import、from…import、as别名
  • 搜索路径:当前目录 → PYTHONPATH → 标准库
  • name:区分导入和直接运行
  • 标准库:math、random、datetime、os、json
  • 最佳实践:文档字符串、all、私有约定

模块是Python代码组织的基础,下一课我们将学习包(Package)——模块的集合。


练习题

  1. 创建一个工具模块,包含常用的字符串处理函数
  2. 探索一个标准库模块(如collections),写出3个使用示例
  3. 理解并解释__name__ == “main“的作用

本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读