🐍 模块与包 — 代码的积木管理
🕐 预计用时:2-3 小时 | 🎯 目标:掌握 import、__name__、pip 安装第三方库、requirements.txt
📖 今日目录
1. 为什么要用模块?
模块就是"工具箱"——把相关功能打包成一个文件,用的时候导入就行。
# 没有模块:所有代码写在一个文件
# calculator.py → 10000 行代码,找 bug 找到崩溃
# 有模块:按功能拆分
# math_utils.py → 数学相关函数
# string_utils.py → 字符串相关函数
# file_utils.py → 文件相关函数
# main.py → 主程序,导入上面的模块
# 这就是模块的价值:组织代码、复用代码、方便维护
| |
|---|
| math |
| datetime |
| os |
| requests |
| json |
| sys |
2. import 导入模块
📖 基本导入
# 导入整个模块
import math
print(math.pi) # 3.141592653589793
print(math.sqrt(16)) # 4.0
print(math.ceil(3.2)) # 4
print(math.floor(3.8)) # 3
# 导入多个模块
import math, random, datetime
# 每个模块单独一行(推荐,更清晰)
import math
import random
import datetime
📛 给模块起别名
# 用 as 起别名(简化长模块名)
import datetime as dt
now = dt.datetime.now()
print(now.strftime("%Y-%m-%d %H:%M:%S"))
# 常见别名约定
import numpy as np # 数据科学标准别名
import pandas as pd # 数据分析标准别名
import matplotlib.pyplot as plt # 绑图标准别名
📋 常用内置模块速查
# math — 数学函数
import math
print(math.pi) # 3.14159...
print(math.e) # 2.71828...
print(math.sqrt(25)) # 5.0
print(math.log(100, 10)) # 2.0
print(math.factorial(5)) # 120
# random — 随机数
import random
print(random.randint(1, 10)) # 1-10 的随机整数
print(random.random()) # 0-1 的随机浮点数
print(random.choice(["a", "b"])) # 随机选一个
print(random.shuffle([1,2,3,4])) # 打乱列表(原地)
# os — 操作系统
import os
print(os.getcwd()) # 当前工作目录
print(os.listdir(".")) # 列出当前目录文件
print(os.path.exists("test.txt")) # 文件是否存在
os.makedirs("new_dir", exist_ok=True) # 创建目录
# sys — 系统相关
import sys
print(sys.version) # Python 版本
print(sys.platform) # 操作系统平台
print(sys.path) # 模块搜索路径
# sys.exit(0) # 退出程序
3. from ... import 精确导入
📖 导入指定内容
# 只导入需要的部分(不用写模块名前缀)
from math import pi, sqrt
print(pi) # 3.14159...(不用写 math.pi)
print(sqrt(25)) # 5.0(不用写 math.sqrt)
# 导入多个
from math import pi, sqrt, ceil, floor
# 导入并起别名
from math import sqrt as sq
print(sq(16)) # 4.0
⚠️ 导入全部(不推荐)
# from math import * # ⚠️ 不推荐!
# 问题:
# 1. 污染当前命名空间(不知道有哪些名字被导入)
# 2. 可能覆盖已有变量
# 3. 代码可读性差(不知道函数来自哪个模块)
# ✅ 推荐写法
from math import sqrt, pi
# ❌ 不推荐
# from math import *
📋 import 三种方式对比
| | | |
|---|
| import math | | |
| from math import sqrt | | |
| from math import * | | |
💡 导入选择原则:
1. 日常开发:import 模块名(清晰明了)
2. 频繁使用某函数:from 模块 import 函数(省代码)
3. from 模块 import *:除非你 100% 确定不会冲突,否则别用
4. __name__ 与 __main__
这是 Python 模块系统的"灵魂特性"——让同一个文件既能被导入,又能直接运行。
# calculator.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
# 这段代码只有直接运行 calculator.py 时才执行
# 被其他文件 import 时不会执行
if __name__ == "__main__":
# 测试代码
print("=== 计算器测试 ===")
print(f"3 + 5 = {add(3, 5)}")
print(f"10 - 4 = {subtract(10, 4)}")
# main.py — 使用 calculator 模块
import calculator
# 只能用函数,测试代码不会运行
result = calculator.add(3, 5)
print(f"结果: {result}") # 结果: 8
🔍 __name__ 的值
# 当文件被直接运行时
# __name__ 的值是 "__main__"
# 当文件被 import 时
# __name__ 的值是模块名(文件名)
# 演示
print(f"当前模块的 __name__: {__name__}")
# 如果直接运行:__name__ = "__main__"
# 如果被导入:__name__ = "calculator"
| __name__ | if __name__ == "__main__" |
|---|
python calculator.py | "__main__" | |
import calculator | "calculator" | |
💡 为什么需要 __name__?
1. 模块可以独立运行(测试、演示)
2. 模块可以被导入复用(不执行测试代码)
3. 一个文件两种用途,不用维护两个文件
每个 Python 文件都应该有 if __name__ == "__main__" 块!
5. 自定义模块
📖 创建自己的模块
# 文件:my_utils.py(这就是一个模块)
"""
我的工具模块
提供字符串和数学相关的工具函数
"""
def reverse_string(s):
"""反转字符串"""
return s[::-1]
def is_palindrome(s):
"""判断是否回文"""
s = s.lower().replace(" ", "")
return s == s[::-1]
def factorial(n):
"""计算阶乘"""
if n <= 1:
return 1
return n * factorial(n - 1)
def fibonacci(n):
"""生成斐波那契数列"""
if n <= 0:
return []
if n == 1:
return [0]
fib = [0, 1]
for i in range(2, n):
fib.append(fib[i-1] + fib[i-2])
return fib
# 模块的测试代码
if __name__ == "__main__":
print(reverse_string("hello")) # olleh
print(is_palindrome("level")) # True
print(factorial(5)) # 120
print(fibonacci(8)) # [0, 1, 1, 2, 3, 5, 8, 13]
# 文件:main.py(使用自定义模块)
import my_utils
print(my_utils.reverse_string("Python")) # nohtyP
print(my_utils.is_palindrome("racecar")) # True
# 或者精确导入
from my_utils import fibonacci
print(fibonacci(10)) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
🔍 模块搜索路径
import sys
# Python 按以下顺序搜索模块:
# 1. 当前目录
# 2. PYTHONPATH 环境变量指定的目录
# 3. 标准库目录
# 4. 第三方库目录(site-packages)
print(sys.path) # 显示搜索路径
# 如果模块不在搜索路径中,可以手动添加
# sys.path.append("/my/custom/path")
6. 包(Package)
包是"文件夹版的模块"——把多个模块组织成一个目录。
# 包的目录结构
my_project/
├── main.py
└── my_package/ ← 这是一个包(有 __init__.py 的文件夹)
├── __init__.py ← 标识这是一个包(可以为空)
├── math_tools.py ← 子模块
├── string_tools.py ← 子模块
└── file_tools.py ← 子模块
# __init__.py(可以为空,也可以有初始化代码)
# 空文件 → 只是标识这是一个包
# 有代码 → 控制包的导入行为
# my_package/math_tools.py
def add(a, b):
return a + b
def multiply(a, b):
return a * b
# my_package/string_tools.py
def capitalize_words(s):
return s.title()
def count_words(s):
return len(s.split())
# my_package/__init__.py
# 可以在这里控制导入行为
from .math_tools import add, multiply
from .string_tools import capitalize_words
# main.py — 使用包
# 方式一:导入整个包
import my_package
print(my_package.add(1, 2))
# 方式二:导入子模块
from my_package import math_tools
print(math_tools.multiply(3, 4))
# 方式三:精确导入
from my_package.math_tools import add
print(add(5, 6))
# 方式四:通过 __init__.py 导入的(最简洁)
from my_package import add
print(add(7, 8))
📦 相对导入 vs 绝对导入
# 绝对导入(从项目根目录开始)
from my_package.math_tools import add
# 相对导入(从当前文件位置开始)
# 在 my_package/string_tools.py 中:
from .math_tools import add # 同级目录
from ..other_package import utils # 上一级目录
💡 包 vs 模块:
模块 = 一个 .py 文件
包 = 一个包含 __init__.py 的文件夹(里面可以有多个模块)
项目大了就用包来组织,小项目一个模块就够。
7. pip:第三方库管理
pip 是 Python 的"应用商店"——用来安装别人写好的库。
📋 常用 pip 命令
# 安装库
pip install requests
pip install numpy pandas matplotlib # 一次安装多个
# 指定版本安装
pip install requests==2.31.0 # 精确版本
pip install "requests>=2.28,<3.0" # 版本范围
# 升级库
pip install --upgrade requests
# 卸载库
pip uninstall requests
# 查看已安装的库
pip list
# 查看某个库的信息
pip show requests
# 搜索库(已弃用,改用 PyPI 网站)
# pip search requests # ⚠️ 已禁用
# 导出依赖
pip freeze > requirements.txt
# 从文件安装依赖
pip install -r requirements.txt
🌐 国内镜像源(加速下载)
# 临时使用
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
# 永久配置(推荐)
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# 常用镜像源
# 清华: https://pypi.tuna.tsinghua.edu.cn/simple
# 阿里: https://mirrors.aliyun.com/pypi/simple
# 腾讯: https://mirrors.cloud.tencent.com/pypi/simple
# 华为: https://repo.huaweicloud.com/repository/pypi/simple
📦 常用第三方库推荐
| | |
|---|
| requests | |
flask | |
django | |
| numpy | |
pandas | |
matplotlib | |
| selenium | |
beautifulsoup4 | |
| rich | |
python-dotenv | |
💡 pip 常见问题:
1. pip 不存在 → 用 pip3 或 python -m pip
2. 下载太慢 → 配置国内镜像源
3. 权限不够 → 加 --user 或用虚拟环境
4. 版本冲突 → 用虚拟环境隔离
8. requirements.txt:依赖管理
requirements.txt 是项目的"购物清单"——记录需要安装哪些库。
# 生成 requirements.txt
pip freeze > requirements.txt
# 文件内容示例
# requests==2.31.0
# flask==3.0.0
# numpy==1.26.2
# pandas==2.1.4
# 别人拿到你的项目后,一键安装所有依赖
pip install -r requirements.txt
📝 requirements.txt 格式
# 精确版本(推荐用于生产环境)
requests==2.31.0
flask==3.0.0
# 最低版本
requests>=2.28.0
# 版本范围
requests>=2.28,<3.0
# 最新版本(不推荐,可能有兼容问题)
requests
# 从 Git 安装
git+https://github.com/user/repo.git
# 注释
requests==2.31.0 # HTTP 请求库
flask==3.0.0 # Web 框架
🏗️ 虚拟环境(最佳实践)
# 创建虚拟环境
python -m venv myenv
# 激活虚拟环境
# Windows:
myenv\Scripts\activate
# macOS/Linux:
source myenv/bin/activate
# 激活后,pip install 只影响当前环境
pip install requests # 只装在 myenv 里
# 退出虚拟环境
deactivate
# 为什么用虚拟环境?
# 1. 项目 A 需要 requests 2.28,项目 B 需要 requests 2.31
# 2. 不污染系统 Python 环境
# 3. 方便部署和迁移
💡 项目最佳实践:
1. 每个项目一个虚拟环境
2. 维护 requirements.txt
3. 用 pip freeze > requirements.txt 更新依赖
4. 部署时 pip install -r requirements.txt
9. 实战练习
🎯 练习 1:密码工具模块
# password_utils.py
"""
密码工具模块
提供密码生成、强度检查、哈希等功能
"""
import random
import string
import hashlib
def generate_password(length=16, use_special=True):
"""生成随机密码"""
chars = string.ascii_letters + string.digits
if use_special:
chars += "!@#$%^&*"
# 确保至少包含各种字符
password = [
random.choice(string.ascii_uppercase),
random.choice(string.ascii_lowercase),
random.choice(string.digits),
]
if use_special:
password.append(random.choice("!@#$%^&*"))
# 填充剩余长度
for _ in range(length - len(password)):
password.append(random.choice(chars))
random.shuffle(password)
return "".join(password)
def check_strength(password):
"""检查密码强度"""
score = 0
feedback = []
if len(password) >= 8:
score += 1
else:
feedback.append("长度不足8位")
if any(c.isupper() for c in password):
score += 1
else:
feedback.append("缺少大写字母")
if any(c.islower() for c in password):
score += 1
else:
feedback.append("缺少小写字母")
if any(c.isdigit() for c in password):
score += 1
else:
feedback.append("缺少数字")
special = "!@#$%^&*()_+-=[]{}|;:',.<>?"
if any(c in special for c in password):
score += 1
else:
feedback.append("缺少特殊字符")
levels = {0: "极弱", 1: "弱", 2: "一般", 3: "中等", 4: "强", 5: "极强"}
return score, levels[score], feedback
def hash_password(password, algorithm="sha256"):
"""哈希密码"""
h = hashlib.new(algorithm)
h.update(password.encode("utf-8"))
return h.hexdigest()
# 测试代码
if __name__ == "__main__":
print("=== 密码工具测试 ===")
# 生成密码
for i in range(3):
pwd = generate_password(12)
score, level, _ = check_strength(pwd)
print(f" {pwd} | {level} ({score}/5)")
# 检查强度
test_pwd = "MyP@ss2024!"
score, level, feedback = check_strength(test_pwd)
print(f"\n密码: {test_pwd}")
print(f"强度: {level} ({score}/5)")
print(f"哈希: {hash_password(test_pwd)[:32]}...")
🎯 练习 2:简易包结构
# 项目结构
# my_tools/
# ├── __init__.py
# ├── math_tools.py
# ├── text_tools.py
# └── list_tools.py
# my_tools/__init__.py
"""
我的工具包
"""
from .math_tools import average, percentage
from .text_tools import word_count, char_count
from .list_tools import flatten, unique
# my_tools/math_tools.py
def average(numbers):
"""计算平均值"""
return sum(numbers) / len(numbers) if numbers else 0
def percentage(part, total):
"""计算百分比"""
return round(part / total * 100, 2) if total else 0
# my_tools/text_tools.py
def word_count(text):
"""统计单词数"""
return len(text.split())
def char_count(text, include_spaces=True):
"""统计字符数"""
if include_spaces:
return len(text)
return len(text.replace(" ", ""))
# my_tools/list_tools.py
def flatten(nested):
"""扁平化嵌套列表"""
result = []
for item in nested:
if isinstance(item, list):
result.extend(flatten(item))
else:
result.append(item)
return result
def unique(items):
"""去重并保持顺序"""
seen = set()
result = []
for item in items:
if item not in seen:
seen.add(item)
result.append(item)
return result
# 使用示例
from my_tools import average, word_count, flatten
print(average([85, 90, 78, 92])) # 86.25
print(word_count("hello world python")) # 3
print(flatten([[1, 2], [3, [4, 5]]])) # [1, 2, 3, 4, 5]
🎯 练习 3:配置管理器
# config_manager.py
"""
配置管理模块
支持 JSON 配置文件的读写和管理
"""
import json
import os
class ConfigManager:
"""配置管理器"""
def __init__(self, config_file="config.json"):
self.config_file = config_file
self.config = {}
self.load()
def load(self):
"""加载配置文件"""
if os.path.exists(self.config_file):
try:
with open(self.config_file, "r", encoding="utf-8") as f:
self.config = json.load(f)
except json.JSONDecodeError as e:
print(f"⚠️ 配置文件格式错误: {e}")
self.config = {}
else:
self.config = {}
def save(self):
"""保存配置到文件"""
with open(self.config_file, "w", encoding="utf-8") as f:
json.dump(self.config, f, indent=2, ensure_ascii=False)
def get(self, key, default=None):
"""获取配置项"""
return self.config.get(key, default)
def set(self, key, value):
"""设置配置项"""
self.config[key] = value
self.save() # 自动保存
def delete(self, key):
"""删除配置项"""
if key in self.config:
del self.config[key]
self.save()
return True
return False
def keys(self):
"""获取所有配置项名称"""
return list(self.config.keys())
def __str__(self):
return json.dumps(self.config, indent=2, ensure_ascii=False)
# 测试
if __name__ == "__main__":
config = ConfigManager("test_config.json")
# 设置配置
config.set("app_name", "我的应用")
config.set("version", "1.0.0")
config.set("debug", True)
config.set("max_retries", 3)
# 读取配置
print(f"应用名: {config.get('app_name')}")
print(f"版本: {config.get('version')}")
print(f"调试模式: {config.get('debug')}")
# 显示所有配置
print(f"\n所有配置:\n{config}")
# 删除配置
config.delete("debug")
print(f"\n删除后:\n{config}")
10. 今日小结
| |
|---|
| import module |
| from module import func |
| 直接运行 = "__main__",被导入 = 模块名 |
| |
| 有 __init__.py 的文件夹,组织多个模块 |
| install / uninstall / list / freeze |
| |
| |
| python -m venv |
🧠 记忆口诀:
import 导模块,from 精确取。
name 是 main,独立运行起。
init 标识包,pip 装工具。
freeze 列清单,venv 隔离地。
🔮 预告: Day 19 推导式 — 列表/字典/集合推导式、生成器表达式。Python 最优雅的语法糖!