
引言:为什么需要模块和包?
在前面的课程中,我们把所有代码都写在一个文件里。但当程序越来越复杂时,一个文件会变得非常长,难以维护。
这时候就需要用到模块 和包:
- 模块:一个.py文件就是一个模块
- 包:包含多个模块的目录
通过模块和包,我们可以:
- 把代码组织成多个文件
- 复用已有的代码
- 使用别人写好的库
模块和包是Python代码组织的基础,掌握了它们,你就能编写更大、更复杂的程序了。
一、导入模块
1. 什么是模块
模块是一个包含Python代码的.py文件。模块可以定义函数、类和变量,也可以包含可执行的代码。
python
# math_module.py
import math
def circle_area(radius):
"""计算圆的面积"""
return math.pi * radius ** 2
def circle_perimeter(radius):
"""计算圆的周长"""
return 2 * math.pi * radius
PI = math.pi
2. import语句
使用 import 语句导入整个模块。
python
# 导入整个模块
import math
# 使用模块中的函数
print(math.sqrt(16)) # 输出:4.0
print(math.pi) # 输出:3.141592653589793
# 导入多个模块
import os
import sys
print(os.getcwd())
print(sys.version)
3. from...import语句
使用 from...import 语句导入模块中的特定内容。
python
# 导入特定的函数
from math import sqrt, pi
print(sqrt(16)) # 输出:4.0
print(pi) # 输出:3.141592653589793
# 导入所有内容(不推荐)
from math import *
print(sqrt(16)) # 可以直接使用,不需要math.前缀
💡 提示:
import module:需要使用module.function()调用from module import function:可以直接使用function()调用from module import *:导入所有内容,但可能导致命名冲突
4. as别名
使用 as 关键字给模块或函数起别名。
python
# 给模块起别名
import numpy as np
arr = np.array([1, 2, 3])
print(arr)
# 给函数起别名
from math import sqrt as square_root
print(square_root(16)) # 输出:4.0
# 常用别名
import pandas as pd
import matplotlib.pyplot as plt
5. 导入自定义模块
python
# mymodule.py
def greet(name):
return f"Hello, {name}!"
PI = 3.14159
# main.py
import mymodule
print(mymodule.greet("小明")) # 输出:Hello, 小明!
print(mymodule.PI) # 输出:3.14159
6. __name__变量
__name__ 是Python的特殊变量,用于判断模块是被直接运行还是被导入。
python
# mymodule.py
def main():
print("这是主函数")
if __name__ == "__main__":
# 只有直接运行此文件时才会执行
main()
print("直接运行mymodule.py")
else:
# 被其他文件导入时不会执行
print("mymodule.py被导入")
💡 提示:
- 直接运行文件时,
__name__等于"__main__"- 被导入时,
__name__等于模块名
二、创建自己的模块
1. 创建简单模块
python
# calculator.py
"""
计算器模块
提供基本的数学运算功能
"""
def add(a, b):
"""加法"""
return a + b
def subtract(a, b):
"""减法"""
return a - b
def multiply(a, b):
"""乘法"""
return a * b
def divide(a, b):
"""除法"""
if b == 0:
raise ValueError("除数不能为零")
return a / b
# 测试代码
if __name__ == "__main__":
print("测试计算器模块")
print(f"2 + 3 = {add(2, 3)}")
print(f"5 - 2 = {subtract(5, 2)}")
print(f"4 * 3 = {multiply(4, 3)}")
print(f"6 / 2 = {divide(6, 2)}")
2. 模块的文档字符串
python
"""
学生管理模块
提供学生信息的增删改查功能。
作者:全栈弄潮儿
版本:1.0
日期:2024-01-01
"""
class Student:
"""学生类"""
def __init__(self, student_id, name, age):
self.student_id = student_id
self.name = name
self.age = age
def info(self):
"""显示学生信息"""
print(f"学号:{self.student_id},姓名:{self.name},年龄:{self.age}")
def create_student(student_id, name, age):
"""创建学生对象"""
return Student(student_id, name, age)
3. 模块的__all__变量
__all__ 用于控制 from module import * 时导入的内容。
python
# mymodule.py
__all__ = ["public_function", "PublicClass"]
def public_function():
"""公开函数"""
pass
def _private_function():
"""私有函数(不会被import *导入)"""
pass
class PublicClass:
"""公开类"""
pass
class _PrivateClass:
"""私有类(不会被import *导入)"""
pass
4. 模块搜索路径
Python按照以下顺序搜索模块:
- 当前目录
- PYTHONPATH环境变量中的目录
- 默认路径(安装时设置的目录)
python
import sys
# 查看模块搜索路径
for path in sys.path:
print(path)
# 添加搜索路径
sys.path.append("/path/to/your/module")
三、包的组织
1. 什么是包
包是包含多个模块的目录,用于组织相关的模块。
markdown
my_package/
__init__.py
module1.py
module2.py
subpackage/
__init__.py
module3.py
2. 创建包
markdown
# 目录结构
math_package/
__init__.py
basic.py
advanced.py
python
# math_package/__init__.py
"""
数学包
提供基本和高级数学运算功能
"""
from .basic import add, subtract
from .advanced import power, sqrt
__all__ = ["add", "subtract", "power", "sqrt"]
__version__ = "1.0.0"
python
# math_package/basic.py
"""基本数学运算"""
def add(a, b):
return a + b
def subtract(a, b):
return a - b
python
# math_package/advanced.py
"""高级数学运算"""
import math
def power(base, exponent):
return base ** exponent
def sqrt(x):
return math.sqrt(x)
python
# 使用包
import math_package
print(math_package.add(2, 3)) # 输出:5
print(math_package.sqrt(16)) # 输出:4.0
# 导入特定模块
from math_package import basic
print(basic.add(2, 3))
# 导入特定函数
from math_package.advanced import power
print(power(2, 10)) # 输出:1024
3. init.py的作用
__init__.py 文件有以下作用:
- 标识目录为Python包
- 初始化包
- 控制包的公开接口
python
# my_package/__init__.py
# 1. 设置包的版本
__version__ = "1.0.0"
# 2. 导入子模块
from . import module1
from . import module2
# 3. 设置公开接口
__all__ = ["module1", "module2", "public_function"]
# 4. 初始化代码
print("包被导入")
def public_function():
"""公开函数"""
pass
4. 相对导入和绝对导入
python
# 目录结构
package/
__init__.py
module1.py
subpackage/
__init__.py
module2.py
# package/subpackage/module2.py
# 绝对导入(推荐)
from package import module1
# 相对导入
from .. import module1 # 导入父包中的module1
from . import module3 # 导入同包中的module3
💡 提示:
- 绝对导入更清晰,推荐使用
- 相对导入只在包内部使用
四、pip安装第三方库
1. 什么是pip
pip 是Python的包管理工具,用于安装和管理第三方库。
bash
# 查看pip版本
pip --version
# 升级pip
python -m pip install --upgrade pip
2. 安装第三方库
bash
# 安装单个库
pip install requests
# 安装指定版本
pip install requests==2.28.0
# 安装多个库
pip install requests numpy pandas
# 从requirements.txt安装
pip install -r requirements.txt
3. requirements.txt
requirements.txt 文件用于记录项目依赖。
txt
# requirements.txt
requests==2.28.0
numpy>=1.21.0
pandas>=1.3.0
flask>=2.0.0
bash
# 生成requirements.txt
pip freeze > requirements.txt
# 从requirements.txt安装
pip install -r requirements.txt
4. 常用第三方库
bash
# 数据处理
pip install numpy pandas
# 网络请求
pip install requests
# Web开发
pip install flask django
# 数据可视化
pip install matplotlib seaborn
# 机器学习
pip install scikit-learn tensorflow pytorch
# 爬虫
pip install beautifulsoup4 scrapy
# 数据库
pip install sqlalchemy pymysql
5. 虚拟环境
虚拟环境可以为每个项目创建独立的Python环境。
bash
# 创建虚拟环境
python -m venv myenv
# 激活虚拟环境
# Windows
myenv\Scripts\activate
# macOS/Linux
source myenv/bin/activate
# 退出虚拟环境
deactivate
# 在虚拟环境中安装包
pip install requests
💡 提示:
- 每个项目使用独立的虚拟环境
- 避免不同项目的依赖冲突
- 方便部署和分享
五、常用标准库
1. os模块
python
import os
# 当前工作目录
print(os.getcwd())
# 切换目录
os.chdir("/path/to/dir")
# 列出目录内容
print(os.listdir("."))
# 创建目录
os.mkdir("new_dir")
# 删除目录
os.rmdir("new_dir")
# 删除文件
os.remove("file.txt")
# 路径操作
path = os.path.join("folder", "subfolder", "file.txt")
print(path)
print(os.path.exists("file.txt"))
print(os.path.isfile("file.txt"))
print(os.path.isdir("folder"))
2. sys模块
python
import sys
# Python版本
print(sys.version)
# 命令行参数
print(sys.argv)
# 退出程序
sys.exit(0)
# 模块搜索路径
print(sys.path)
# 标准输入输出
sys.stdout.write("Hello\n")
sys.stderr.write("Error\n")
3. datetime模块
python
from datetime import datetime, timedelta
# 当前时间
now = datetime.now()
print(now)
# 格式化时间
print(now.strftime("%Y-%m-%d %H:%M:%S"))
# 解析时间
dt = datetime.strptime("2024-01-01 12:00:00", "%Y-%m-%d %H:%M:%S")
print(dt)
# 时间计算
tomorrow = now + timedelta(days=1)
print(tomorrow)
# 时间差
delta = tomorrow - now
print(delta.days)
4. json模块
python
import json
# Python对象转JSON字符串
data = {"name": "小明", "age": 20}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
# JSON字符串转Python对象
parsed = json.loads(json_str)
print(parsed)
# 写入JSON文件
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 读取JSON文件
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
print(data)
5. random模块
python
import random
# 随机整数
print(random.randint(1, 10))
# 随机浮点数
print(random.random())
# 随机选择
fruits = ["苹果", "香蕉", "橙子"]
print(random.choice(fruits))
# 随机打乱
random.shuffle(fruits)
print(fruits)
# 生成随机样本
print(random.sample(range(100), 5))
六、实战练习
练习1:创建工具模块
python
# utils.py
"""
工具模块
提供常用的工具函数
"""
import os
import json
from datetime import datetime
def ensure_dir(path):
"""确保目录存在"""
if not os.path.exists(path):
os.makedirs(path)
def load_json(filepath):
"""加载JSON文件"""
with open(filepath, "r", encoding="utf-8") as f:
return json.load(f)
def save_json(data, filepath):
"""保存JSON文件"""
with open(filepath, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def get_timestamp():
"""获取当前时间戳"""
return datetime.now().strftime("%Y%m%d_%H%M%S")
def format_size(size_bytes):
"""格式化文件大小"""
for unit in ["B", "KB", "MB", "GB"]:
if size_bytes < 1024:
return f"{size_bytes:.2f} {unit}"
size_bytes /= 1024
return f"{size_bytes:.2f} TB"
# 测试
if __name__ == "__main__":
print("测试工具模块")
print(f"时间戳:{get_timestamp()}")
print(f"文件大小:{format_size(1024 * 1024 * 5)}")
练习2:创建配置管理包
arduino
config_manager/
__init__.py
config.py
validator.py
python
# config_manager/__init__.py
"""
配置管理包
"""
from .config import Config
from .validator import validate_config
__all__ = ["Config", "validate_config"]
__version__ = "1.0.0"
python
# config_manager/config.py
"""
配置类
"""
import json
import os
class Config:
"""配置管理类"""
def __init__(self, config_file="config.json"):
self.config_file = config_file
self.data = {}
self.load()
def load(self):
"""加载配置"""
if os.path.exists(self.config_file):
with open(self.config_file, "r", encoding="utf-8") as f:
self.data = json.load(f)
def save(self):
"""保存配置"""
with open(self.config_file, "w", encoding="utf-8") as f:
json.dump(self.data, f, ensure_ascii=False, indent=2)
def get(self, key, default=None):
"""获取配置项"""
return self.data.get(key, default)
def set(self, key, value):
"""设置配置项"""
self.data[key] = value
self.save()
python
# config_manager/validator.py
"""
配置验证器
"""
def validate_config(config_data, schema):
"""验证配置是否符合schema"""
errors = []
for key, rules in schema.items():
if rules.get("required") and key not in config_data:
errors.append(f"缺少必填项:{key}")
continue
if key in config_data:
value = config_data[key]
expected_type = rules.get("type")
if expected_type and not isinstance(value, expected_type):
errors.append(f"{key}类型错误,期望{expected_type}")
return errors
练习3:使用第三方库
python
# 使用requests库
import requests
def fetch_data(url):
"""获取网络数据"""
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"请求失败:{e}")
return None
# 使用pandas库
import pandas as pd
def analyze_csv(filepath):
"""分析CSV文件"""
df = pd.read_csv(filepath)
print(f"数据形状:{df.shape}")
print(f"列名:{df.columns.tolist()}")
print(f"统计信息:\n{df.describe()}")
return df
# 使用matplotlib库
import matplotlib.pyplot as plt
def plot_data(data):
"""绘制数据图表"""
plt.figure(figsize=(10, 6))
plt.plot(data)
plt.title("数据趋势图")
plt.xlabel("X轴")
plt.ylabel("Y轴")
plt.grid(True)
plt.savefig("plot.png")
plt.show()
七、常见问题与排错
问题1:ModuleNotFoundError
原因 :找不到模块 解决方法:检查模块路径和名称
python
# ❌ 错误
import mymodule # ModuleNotFoundError
# ✅ 解决方法1:确保模块在当前目录或PYTHONPATH中
# ✅ 解决方法2:添加路径
import sys
sys.path.append("/path/to/module")
import mymodule
问题2:循环导入
原因 :两个模块互相导入 解决方法:重构代码,避免循环依赖
python
# ❌ 错误:循环导入
# a.py
import b
# b.py
import a
# ✅ 解决方法:重构代码结构
# 将共同依赖的代码提取到第三个模块
问题3:pip安装失败
原因 :网络问题或源不可用 解决方法:使用国内镜像源
bash
# 使用清华镜像
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests
# 永久设置镜像
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
八、本篇小结
今天,我们完成了以下学习内容:
-
导入模块:
import module导入整个模块from module import name导入特定内容as起别名__name__判断模块运行方式
-
创建自己的模块:
- 一个.py文件就是一个模块
- 使用文档字符串说明模块
- 使用
__all__控制公开接口
-
包的组织:
- 包是包含多个模块的目录
__init__.py标识和初始化包- 相对导入和绝对导入
-
pip安装第三方库:
pip install安装库requirements.txt管理依赖- 虚拟环境隔离项目
请记住这三个结论:
- 模块是代码组织的基本单位:一个.py文件就是一个模块
- 包用于组织相关模块 :包含
__init__.py的目录就是包 - pip是Python的包管理器:用于安装和管理第三方库
下期预告
在第14期中,我们将学习Python的装饰器和生成器,包括:
- 装饰器的概念和语法
- 带参数的装饰器
- 生成器的使用
- yield关键字
敬请期待!
✍坚持原创,求关注,点赞,收藏