Python 常用内建模块:开箱即用的"瑞士军刀"
引言:Python 的"标配工具箱"
买新手机时,厂商会预装一堆基础 App:计算器、日历、备忘录……你不需要去应用商店下载,开机就能用。
Python 也一样。安装 Python 解释器的那一刻,你就自动获得了几百个内建模块(Built-in Modules)——它们由 Python 官方开发和维护,质量可靠、开箱即用,覆盖日期处理、数据结构、加密、网络、命令行参数等方方面面。
有句话叫"Python 自带电池(Batteries Included)",说的就是这套丰富的标准库。很多你以为要装第三方库才能实现的功能,标准库里早就有了。
这一篇,我们挑选日常开发中最常用的 13 个内建模块,用生活化的案例讲清楚每个模块是干什么的、怎么用、有什么坑。
一、datetime:处理日期和时间的"电子日历"
1.1 解决什么问题?
程序中经常要处理时间:记录日志、计算超时、判断活动时间……但时间处理比想象中复杂——闰年、时区、夏令时,手写计算分分钟出错。
datetime 模块就是 Python 官方的"电子日历"。
1.2 核心类
| 类 | 含义 | 例子 |
|---|---|---|
datetime | 日期 + 时间 | 2026-08-28 14:30:00 |
date | 只有日期 | 2026-08-28 |
time | 只有时间 | 14:30:00 |
timedelta | 时间差 | 3 天 2 小时 |
1.3 常用操作
from datetime import datetime, timedelta
# 获取当前时间
now = datetime.now()
print(now) # 2026-08-28 14:30:15.123456
# 手动构造一个时间
dt = datetime(2026, 10, 1, 8, 0, 0)
print(dt) # 2026-10-01 08:00:00
# 时间加减(国庆后 7 天是哪天?)
future = dt + timedelta(days=7)
print(future) # 2026-10-08 08:00:00
# 时间差
delta = future - now
print(delta.days) # 相差多少天
# 格式化输出(strftime)
print(now.strftime('%Y-%m-%d %H:%M:%S')) # 2026-08-28 14:30:15
print(now.strftime('%Y年%m月%d日')) # 2026年08月28日
# 字符串解析成时间(strptime)
dt = datetime.strptime('2026-08-28', '%Y-%m-%d')
print(dt) # 2026-08-28 00:00:001.4 时间戳转换
**时间戳(timestamp)**是从 1970 年 1 月 1 日 0 点(UTC)到现在的秒数,计算机之间传时间都用它:
# datetime → 时间戳
ts = datetime.now().timestamp()
print(ts) # 1787947815.123456
# 时间戳 → datetime
dt = datetime.fromtimestamp(ts)
print(dt) # 2026-08-28 14:30:15.1234561.5 常见误区
误区:strftime 和 strptime 傻傻分不清。
strftime:format,把时间格式化为字符串(时间 → 字符串);strptime:parse,把字符串解析为时间(字符串 → 时间)。
记忆技巧:f = 发(format 发出去),p = 收(parse 收回来)。
二、collections:数据结构"加强包"
2.1 解决什么问题?
Python 内置的 list、dict、tuple 很好用,但有些场景力不从心。collections 模块提供了一批"加强版"数据结构。
2.2 Counter:自动计数器
生活化场景:统计一篇文章中每个单词出现的次数。
from collections import Counter
words = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
c = Counter(words)
print(c) # Counter({'apple': 3, 'banana': 2, 'orange': 1})
print(c.most_common(2)) # [('apple', 3), ('banana', 2)] — 出现最多的前2个不用 Counter 你得自己写循环 + 字典判断,用了它一行搞定。
2.3 defaultdict:永不报错的字典
普通字典访问不存在的 key 会报 KeyError,defaultdict 会自动给个默认值:
from collections import defaultdict
# 默认值为 int(即 0)的字典
d = defaultdict(int)
d['苹果'] += 1
d['苹果'] += 1
d['香蕉'] += 1
print(d) # defaultdict(<class 'int'>, {'苹果': 2, '香蕉': 1})
# 默认值为 list 的字典(分组利器)
students = [('一班', '小明'), ('二班', '小红'), ('一班', '小刚')]
groups = defaultdict(list)
for cls, name in students:
groups[cls].append(name)
print(groups) # {'一班': ['小明', '小刚'], '二班': ['小红']}2.4 OrderedDict 和 deque
from collections import deque
# deque:双端队列,两头都能快速进出
# 生活化理解:像一管牙膏,可以从前面挤也可以从后面推
q = deque([1, 2, 3])
q.append(4) # 尾部加入 → [1, 2, 3, 4]
q.appendleft(0) # 头部加入 → [0, 1, 2, 3, 4]
q.pop() # 尾部弹出 → 4
q.popleft() # 头部弹出 → 0什么时候用 deque 而不是 list? 需要频繁在头部插入/删除时。list 在头部操作是 O(n)(所有元素都要移动),deque 是 O(1)。
2.5 namedtuple:带名字的元组
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p.x, p.y) # 1 2 — 可以用属性名访问,比 p[0] p[1] 清晰生活化理解:普通元组像一张没有表头的表格(('张三', 18, '男')——哪个是年龄?),namedtuple 给每一列加了表头。
三、argparse:命令行参数的"前台接待"
3.1 解决什么问题?
你写了一个脚本 backup.py,希望用户这样用:
python backup.py --source /data --target /backup --compress--source、--target 这些参数怎么解析?手写 sys.argv 解析又麻烦又容易错。argparse 就是专业的"参数前台"。
3.2 基本用法
# backup.py
import argparse
parser = argparse.ArgumentParser(description='文件备份工具')
parser.add_argument('--source', required=True, help='源目录')
parser.add_argument('--target', required=True, help='目标目录')
parser.add_argument('--compress', action='store_true', help='是否压缩')
parser.add_argument('--retry', type=int, default=3, help='失败重试次数')
args = parser.parse_args()
print(f'从 {args.source} 备份到 {args.target}')
print(f'压缩: {args.compress}, 重试: {args.retry}')运行效果:
$ python backup.py --source /data --target /backup --compress
从 /data 备份到 /backup
压缩: True, 重试: 3
$ python backup.py --help # 自动生成帮助文档!
usage: backup.py [-h] --source SOURCE --target TARGET [--compress] [--retry RETRY]
文件备份工具
options:
-h, --help show this help message and exit
--source SOURCE 源目录
--target TARGET 目标目录
--compress 是否压缩
--retry RETRY 失败重试次数3.3 常用参数选项
| 选项 | 作用 | 例子 |
|---|---|---|
required=True | 必填参数 | 缺少时报错退出 |
type=int | 类型转换 | 自动转成 int |
default=3 | 默认值 | 不传时用默认值 |
action='store_true' | 开关标志 | 出现即 True |
choices=['a','b'] | 限制可选值 | 防止乱填 |
四、base64:二进制数据的"翻译官"
4.1 解决什么问题?
有些场合只能传输文本(如 Email、URL、JSON),但你要传的是二进制(图片、文件)。怎么办?
Base64 把任意二进制数据翻译成 64 个可打印字符(A-Z、a-z、0-9、+、/),让二进制数据能"混进"纯文本的地盘。
生活化理解:快递违禁品不能寄,但把东西拆成零件、每件贴上标签就能寄了。Base64 就是这个"拆分 + 贴标签"的过程。
4.2 基本用法
import base64
# 编码:字节 → Base64 字节
data = b'hello'
encoded = base64.b64encode(data)
print(encoded) # b'aGVsbG8='
# 解码:Base64 字节 → 原始字节
decoded = base64.b64decode(encoded)
print(decoded) # b'hello'
# 实战:把图片转成 Base64 字符串(可嵌入 HTML)
with open('logo.png', 'rb') as f:
b64_str = base64.b64encode(f.read()).decode('ascii')
html_img = f'<img src="data:image/png;base64,{b64_str}">'4.3 常见误区
误区 1:Base64 是加密。
真相:Base64 只是编码,不是加密!任何人都能解回来。想加密请用下面的 hmac 或专业加密库。
误区 2:Base64 后数据更小。
真相:恰恰相反,Base64 编码后体积增大约 33%(每 3 字节变 4 字符)。它牺牲体积换兼容性。
五、struct:字节流的"打包师傅"
5.1 解决什么问题?
当你要和底层打交道——解析二进制文件(图片头、音频头)、网络协议封包——需要把 Python 的整数、浮点数精确转换成固定长度的字节串,或反过来。struct 就是干这个的。
生活化理解:struct 像快递打包员,把不同形状的物品(int、float)装进标准尺寸的箱子(固定字节数),对方按同样的规则拆箱。
5.2 基本用法
import struct
# 打包:把数据变成字节
# 'I' = 无符号整数(4字节), 'f' = 浮点数(4字节)
data = struct.pack('If', 1024, 3.14)
print(data) # b'\x00\x04\x00\x00\xc3\xf5H@'
# 解包:把字节还原成数据
num, pi = struct.unpack('If', data)
print(num, pi) # 1024 3.1400001049041755.3 实战:解析 BMP 文件头
BMP 图片的前 2 个字节是 'BM',第 3~6 字节是文件大小:
import struct
with open('test.bmp', 'rb') as f:
header = f.read(30)
# '<' 小端序, '2s' 两字节字符串, 'I' 无符号整数
magic, file_size = struct.unpack('<2sI', header[:6])
print(magic) # b'BM'
print(file_size) # 文件字节数5.4 常用格式符
| 格式符 | 类型 | 字节数 |
|---|---|---|
b | 有符号字符 | 1 |
B | 无符号字符 | 1 |
h | 短整数 | 2 |
I | 无符号整数 | 4 |
q | 长整数 | 8 |
f | 浮点数 | 4 |
d | 双精度浮点 | 8 |
ns | n 字节字符串 | n |
提示:格式串前缀
<表示小端序、>表示大端序(网络字节序),跨机器传输数据时必须明确指定。
六、hashlib:数据的"指纹生成器"
6.1 解决什么问题?
怎么验证下载的文件没损坏?怎么存用户密码才不会泄露?答案是哈希(摘要)算法——给任意数据算出一个固定长度的"指纹":
- 同样的数据,指纹永远相同;
- 数据改一个比特,指纹天差地别;
- 从指纹无法反推原始数据。
生活化理解:哈希就像人的指纹——指纹能证明"你是你",但没人能根据指纹还原出你整个人。
6.2 基本用法
import hashlib
# MD5(已不安全,仅用于文件校验等非安全场景)
md5 = hashlib.md5()
md5.update('hello'.encode('utf-8'))
print(md5.hexdigest()) # 5d41402abc4b2a76b9719d911017c592
# SHA256(目前推荐)
sha256 = hashlib.sha256()
sha256.update('hello'.encode('utf-8'))
print(sha256.hexdigest())
# 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b98246.3 实战:文件完整性校验
import hashlib
def file_hash(path):
"""计算大文件的 SHA256(分块读取,避免撑爆内存)"""
h = hashlib.sha256()
with open(path, 'rb') as f:
while chunk := f.read(8192): # 每次读 8KB
h.update(chunk)
return h.hexdigest()
print(file_hash('big_file.zip'))下载软件时官网给出的 "SHA256 Checksum" 就是这么用的:你算一遍,和官网一致说明文件没坏。
6.4 实战:密码存储(加盐)
import hashlib
import os
def hash_password(password):
salt = os.urandom(16).hex() # 随机盐值
h = hashlib.sha256((salt + password).encode('utf-8'))
return salt + ':' + h.hexdigest()
def verify(password, stored):
salt, _ = stored.split(':')
return hash_password(password) == stored # 简化演示,实际要取出盐重算
# 数据库存的是 "盐:哈希",黑客拿到也破解不了原始密码什么是"加盐"? 给密码混入一段随机字符串再哈希。这样即使两个人密码相同,存储结果也不同,黑客的"彩虹表"(常见密码哈希对照表)直接失效。
6.5 常见误区
误区:MD5 还能用来存密码。
真相:MD5 和 SHA1 都已被破解(存在碰撞),绝不能用于密码等安全场景。请使用 SHA256 以上,更好的选择是专门的密码哈希算法(bcrypt、argon2)。
七、hmac:带密钥的"防伪印章"
7.1 解决什么问题?
普通哈希能证明"数据没被改",但证明不了"数据是你发的"——因为任何人都能算哈希。
HMAC(Keyed-Hash Message Authentication Code)在哈希时混入密钥:只有知道密钥的人才能算出正确的 HMAC,从而同时实现"防篡改 + 身份验证"。
生活化理解:普通哈希是普通公章,谁都能刻一个;HMAC 是加了特殊防伪纹的公章,只有持密钥的人才能盖出正确的章。
7.2 基本用法
import hmac
import hashlib
key = b'my-secret-key'
message = '转账100元给张三'.encode('utf-8')
# 生成 HMAC
h = hmac.new(key, message, digestmod=hashlib.sha256)
print(h.hexdigest()) # 一串防伪指纹
# 验证方用同样的 key 重算,比对结果
expected = hmac.new(key, message, digestmod=hashlib.sha256).hexdigest()
print(hmac.compare_digest(h.hexdigest(), expected)) # True7.3 典型应用:API 签名验证
import hmac
import hashlib
import time
SECRET = b'server-secret'
def sign_request(params):
"""客户端:对请求参数签名"""
params['timestamp'] = str(int(time.time()))
# 参数排序拼接后签名
content = '&'.join(f'{k}={v}' for k, v in sorted(params.items()))
params['sign'] = hmac.new(SECRET, content.encode(), hashlib.sha256).hexdigest()
return params
def verify_request(params):
"""服务端:验证签名"""
sign = params.pop('sign')
content = '&'.join(f'{k}={v}' for k, v in sorted(params.items()))
expected = hmac.new(SECRET, content.encode(), hashlib.sha256).hexdigest()
# 用 compare_digest 防止时序攻击
return hmac.compare_digest(sign, expected)微信支付、阿里云等开放平台的 API 签名,核心原理就是这个。
八、itertools:迭代的"积木工厂"
8.1 解决什么问题?
循环谁都会写,但排列组合、无限序列、分组聚合这些"花式迭代"自己写又累又容易错。itertools 提供了一组高效的迭代器工具。
8.2 常用工具速览
import itertools
# count:无限计数器
for i in itertools.count(10, 2): # 从10开始,步长2
if i > 20:
break
print(i, end=' ') # 10 12 14 16 18 20
# chain:把多个可迭代对象串成一串
print(list(itertools.chain([1, 2], 'ab', (True,))))
# [1, 2, 'a', 'b', True]
# product:笛卡尔积(嵌套循环的平替)
print(list(itertools.product('AB', [1, 2])))
# [('A', 1), ('A', 2), ('B', 1), ('B', 2)]
# permutations:排列(有序,AB≠BA)
print(list(itertools.permutations('ABC', 2)))
# [('A','B'), ('A','C'), ('B','A'), ('B','C'), ('C','A'), ('C','B')]
# combinations:组合(无序,AB=BA)
print(list(itertools.combinations('ABC', 2)))
# [('A','B'), ('A','C'), ('B','C')]8.3 实战:密码字典生成
import itertools
# 生成所有 4 位数字组合(演示用途)
for pwd in itertools.product('0123456789', repeat=4):
print(''.join(pwd)) # 0000, 0001, ..., 99998.4 实战:分组统计
import itertools
data = [('一班', 90), ('一班', 85), ('二班', 78), ('二班', 92)]
# groupby:相邻相同 key 的分为一组(使用前要先按 key 排序!)
data.sort(key=lambda x: x[0])
for cls, members in itertools.groupby(data, key=lambda x: x[0]):
scores = [s for _, s in members]
print(cls, scores) # 一班 [90, 85] / 二班 [78, 92]8.5 常见误区
误区:groupby 不用排序就能分组。
真相:groupby 只把相邻的相同 key 分一组。如果相同 key 分散在序列各处,会被拆成多个组。所以必须先按 key 排序。
九、contextlib:上下文管理的"贴心管家"
9.1 解决什么问题?
你熟悉的 with open(...) as f 能自动关闭文件。如果想让自己的代码也支持 with 语法怎么办?contextlib 让这件事变得超简单。
9.2 @contextmanager:用生成器写上下文
from contextlib import contextmanager
@contextmanager
def timer(name):
"""一个计时的上下文管理器"""
import time
start = time.time()
print(f'[{name}] 开始')
yield # yield 之前是"进入",之后是"退出"
print(f'[{name}] 结束,耗时 {time.time() - start:.2f} 秒')
with timer('数据处理'):
# 这里是要被计时的代码
sum(range(1000000))输出:
[数据处理] 开始
[数据处理] 结束,耗时 0.03 秒9.3 closing:给不会自动关闭的对象兜底
from contextlib import closing
from urllib.request import urlopen
# urlopen 返回的对象不支持 with,用 closing 包装一下
with closing(urlopen('https://www.python.org')) as page:
content = page.read()9.4 suppress:优雅地忽略异常
from contextlib import suppress
# 以前要这样写
try:
os.remove('maybe_not_exists.txt')
except FileNotFoundError:
pass
# 现在一行搞定
with suppress(FileNotFoundError):
os.remove('maybe_not_exists.txt')十、urllib:内置的"网络快递员"
10.1 解决什么问题?
不想装第三方库 requests,又需要发 HTTP 请求?urllib 是 Python 自带的 HTTP 客户端。
10.2 发 GET 请求
from urllib.request import urlopen, Request
from urllib.parse import urlencode
# 简单 GET
with urlopen('https://httpbin.org/get') as resp:
print(resp.status) # 200
print(resp.read()[:200]) # 前200字节
# 带参数和请求头的 GET
params = urlencode({'name': '张三', 'age': 18})
url = f'https://httpbin.org/get?{params}'
req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
with urlopen(req, timeout=10) as resp:
print(resp.read().decode('utf-8'))10.3 发 POST 请求
from urllib.request import urlopen, Request
from urllib.parse import urlencode
data = urlencode({'username': 'admin', 'password': '123456'}).encode('utf-8')
req = Request('https://httpbin.org/post', data=data, method='POST')
with urlopen(req) as resp:
print(resp.read().decode('utf-8'))10.4 urlencode 与 quote:URL 转义
URL 中不能直接出现中文、空格、特殊字符,必须转义:
from urllib.parse import quote, unquote, urlencode, parse_qs
print(quote('北京')) # %E5%8C%97%E4%BA%AC
print(unquote('%E5%8C%97%E4%BA%AC')) # 北京
print(urlencode({'q': 'Python 教程', 'page': 1}))
# q=Python+%E6%95%99%E7%A8%8B&page=1
print(parse_qs('q=python&page=1'))
# {'q': ['python'], 'page': ['1']}10.5 常见误区
误区:urllib 不好用,应该被放弃。
真相:urllib 接口确实比 requests 啰嗦,但它零依赖——在某些不能装第三方包的环境(受限服务器、嵌入式设备),它是唯一选择。日常开发推荐 requests,了解 urllib 兜底。
十一、XML:结构化文档的"老派翻译官"
11.1 解决什么问题?
XML 是老一代数据交换格式(SOAP、RSS、配置文件、SVG 图片都在用)。虽然现在 JSON 更流行,但大量存量系统还在用 XML。Python 内置 xml.etree.ElementTree 可以解析它。
11.2 解析 XML
import xml.etree.ElementTree as ET
xml_str = '''<?xml version="1.0"?>
<bookstore>
<book id="1">
<title>Python 入门</title>
<price>59.0</price>
</book>
<book id="2">
<title>数据结构</title>
<price>79.0</price>
</book>
</bookstore>'''
root = ET.fromstring(xml_str)
print(root.tag) # bookstore
# 遍历所有 book 节点
for book in root.findall('book'):
title = book.find('title').text
price = float(book.find('price').text)
book_id = book.get('id') # 读取属性
print(f'ID={book_id} 《{title}》 ¥{price}')11.3 生成 XML
import xml.etree.ElementTree as ET
root = ET.Element('students')
stu = ET.SubElement(root, 'student', id='1')
ET.SubElement(stu, 'name').text = '小明'
ET.SubElement(stu, 'score').text = '95'
print(ET.tostring(root, encoding='unicode'))
# <students><student id="1"><name>小明</name><score>95</score></student></students>11.4 常见误区
误区:用正则表达式解析 XML。
真相:XML 是嵌套结构,正则是处理平铺文本的,两者天生不匹配。请使用专门的 XML 解析器。
十二、HTMLParser:HTML 的"流水线上的分拣员"
12.1 解决什么问题?
想从 HTML 里提取信息(爬虫的第一步),但 HTML 语法松散、标签嵌套混乱,正则表示无能为力。html.parser.HTMLParser 用事件驱动的方式解析:遇到一个开始标签、一段文本、一个结束标签,就回调你对应的方法。
生活化理解:HTMLParser 像流水线旁的分拣员——传送带(HTML 文档)不断送来包裹(标签、文本),分拣员按类型分拣:<div> 放这边,文字放那边,</div> 放那边。
12.2 基本用法
from html.parser import HTMLParser
class MyParser(HTMLParser):
def handle_starttag(self, tag, attrs):
"""遇到开始标签时触发"""
print(f'开始标签: <{tag}>, 属性: {dict(attrs)}')
def handle_data(self, data):
"""遇到文本内容时触发"""
text = data.strip()
if text:
print(f'文本: {text}')
def handle_endtag(self, tag):
"""遇到结束标签时触发"""
print(f'结束标签: </{tag}>')
html = '''
<html>
<body>
<h1 class="title">文章标题</h1>
<a href="https://example.com">链接文字</a>
</body>
</html>
'''
parser = MyParser()
parser.feed(html)输出:
开始标签: <html>, 属性: {}
开始标签: <body>, 属性: {}
开始标签: <h1>, 属性: {'class': 'title'}
文本: 文章标题
结束标签: </h1>
开始标签: <a>, 属性: {'href': 'https://example.com'}
文本: 链接文字
结束标签: </a>
...12.3 实战:提取页面所有链接
from html.parser import HTMLParser
class LinkExtractor(HTMLParser):
def __init__(self):
super().__init__()
self.links = []
def handle_starttag(self, tag, attrs):
if tag == 'a':
for name, value in attrs:
if name == 'href':
self.links.append(value)
html = '<a href="/page1">P1</a><a href="/page2">P2</a>'
parser = LinkExtractor()
parser.feed(html)
print(parser.links) # ['/page1', '/page2']提示:复杂的爬虫项目推荐第三方库 BeautifulSoup 或 lxml,接口更友好;HTMLParser 胜在零依赖。
十三、venv:项目环境的"独立套间"
13.1 解决什么问题?
- 项目 A 需要 Django 3.x,项目 B 需要 Django 4.x——同一个 Python 环境装哪个?
- 全局装了一堆包,部署时搞不清项目到底依赖哪些。
venv 为每个项目创建独立的虚拟环境:各自的包、各自的版本,互不干扰。
生活化理解:全局 Python 环境像合租屋的公共厨房,谁的调料都往里放,最后乱成一团。venv 是给每个项目一间独立套间——自带厨房,爱放什么放什么,退租时(删除目录)一清了之。
13.2 基本用法
# 创建虚拟环境(在项目目录下执行)
python -m venv .venv
# 激活
# Windows PowerShell:
.venv\Scripts\Activate.ps1
# Windows CMD:
.venv\Scripts\activate.bat
# macOS/Linux:
source .venv/bin/activate
# 激活后,命令行提示符前面会出现 (.venv)
# 此时 pip 安装的包只存在于这个环境中
pip install requests
# 导出依赖清单
pip freeze > requirements.txt
# 退出虚拟环境
deactivate13.3 团队协作流程
# 同事拿到项目后,重建一模一样的环境
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt13.4 常见误区
误区 1:把 .venv 目录提交到 Git。
真相:虚拟环境体积巨大且与机器绑定,绝不能提交。提交 requirements.txt 就够了,.gitignore 里加上 .venv/。
误区 2:创建后忘了激活。
真相:没激活就用 pip install,包装到全局环境了。激活的标志是命令行提示符前有 (.venv)。
误区 3:venv 能隔离 Python 版本。
真相:venv 使用创建它时的 Python 版本,只隔离第三方包,不换解释器。要切换 Python 版本,需要 pyenv、conda 等工具。
十四、全景速查表
| 模块 | 一句话定位 | 高频用途 |
|---|---|---|
| datetime | 电子日历 | 获取当前时间、时间加减、格式化、解析 |
| collections | 数据结构加强包 | 计数 Counter、安全字典 defaultdict、双端队列 deque |
| argparse | 命令行前台 | 解析脚本参数,自动生成 help |
| base64 | 二进制翻译官 | 二进制 ↔ 文本互转(非加密!) |
| struct | 字节打包师傅 | 解析二进制文件、网络协议封包 |
| hashlib | 指纹生成器 | 文件校验、密码加盐存储 |
| hmac | 防伪印章 | API 签名验证、防篡改 |
| itertools | 迭代积木工厂 | 排列组合、笛卡尔积、分组 |
| contextlib | 上下文管家 | 自定义 with、忽略异常、兜底关闭 |
| urllib | 网络快递员 | 零依赖发 HTTP 请求、URL 转义 |
| xml.etree | XML 翻译官 | 解析/生成 XML 文档 |
| html.parser | HTML 分拣员 | 事件驱动提取网页内容 |
| venv | 独立套间 | 项目依赖隔离 |
记住三句话:
- 写代码前先想想"标准库里有没有",别急着 pip install;
- Base64 是编码不是加密,MD5 是校验不是安全,概念别搞混;
- 每个新项目第一件事:
python -m venv .venv,环境隔离从第一天做起。
参考说明
本文内容基于 Python 官方标准库文档及廖雪峰 Python 教程的"常用内建模块"章节重新整理和扩充,所有示例代码均可在 Python 3.8+ 环境直接运行。