常用内建模块
Python 一直说自己「batteries included」,意思就是你开箱即用,很多实用工具都已经装好了。本章就来聊聊廖雪峰 Python 教程第 16 章里介绍的 13 个常用内建模块,每个模块都只挑最常用、最接地气的 API 和示例,混个脸熟就行,后面用到时再查文档也不慌。
1. datetime —— 日期时间处理
datetime 是处理日期和时间的标准库,模块里最重要的有两个东西:datetime 类和 timedelta 类。
1.1 获取当前时间
from datetime import datetime
now = datetime.now()
print(now)
print(type(now))注意 from datetime import datetime 是导入类,而不是整个模块。如果只写 import datetime,那就要用 datetime.datetime.now()。
1.2 指定一个时间
from datetime import datetime
dt = datetime(2025, 8, 1, 12, 30, 0)
print(dt)参数顺序是 年、月、日、时、分、秒,微秒可以省略。
1.3 时间戳与 datetime 互转
时间戳就是距离 1970-01-01 00:00:00 UTC 的秒数,它跟时区无关。
from datetime import datetime
dt = datetime(2025, 8, 1, 12, 30, 0)
ts = dt.timestamp()
print(ts)
# 转回来
dt2 = datetime.fromtimestamp(ts)
print(dt2)
# 转 UTC 时间
dt_utc = datetime.utcfromtimestamp(ts)
print(dt_utc)1.4 字符串和 datetime 互转
from datetime import datetime
# 字符串 -> datetime
cday = datetime.strptime('2025-08-01 12:30:00', '%Y-%m-%d %H:%M:%S')
print(cday)
# datetime -> 字符串
now = datetime.now()
print(now.strftime('%Y-%m-%d %H:%M:%S'))常用占位符:%Y 年、%m 月、%d 日、%H 时、%M 分、%S 秒。
1.5 时间加减
from datetime import datetime, timedelta
now = datetime.now()
print(now + timedelta(hours=2))
print(now - timedelta(days=1))
print(now + timedelta(days=2, hours=3))1.6 时区处理
from datetime import datetime, timedelta, timezone
# 构造 UTC+8 时区
utc_8 = timezone(timedelta(hours=8))
now = datetime.now()
print(now.replace(tzinfo=utc_8))
# 用 UTC 时间作为基准再转时区
utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
bj_dt = utc_dt.astimezone(utc_8)
print(bj_dt)经验之谈:要存时间最好存时间戳,不涉及时区;要展示再转成字符串并带上时区。
2. collections —— 集合增强工具箱
collections 提供了一堆比 list、dict 更顺手的集合类。
2.1 namedtuple
给 tuple 起名字,读取属性更直观。
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(p.x, p.y)
print(isinstance(p, tuple)) # True2.2 deque
双端队列,头部和尾部插入、删除都很快。
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
print(q)
print(q.pop())
print(q.popleft())2.3 defaultdict
访问不存在的 key 时返回默认值,而不是抛 KeyError。
from collections import defaultdict
dd = defaultdict(lambda: 'N/A')
dd['name'] = 'juzicoding'
print(dd['name'])
print(dd['age']) # 不存在,返回默认值2.4 OrderedDict
按插入顺序保存 key 的字典。
from collections import OrderedDict
od = OrderedDict()
od['z'] = 1
od['y'] = 2
od['x'] = 3
print(list(od.keys()))2.5 ChainMap
把多个字典串起来,按顺序查找,适合做「命令行参数 > 环境变量 > 默认值」这种优先级。
from collections import ChainMap
defaults = {'color': 'red', 'user': 'guest'}
command_line = {'user': 'bob'}
combined = ChainMap(command_line, defaults)
print(combined['user']) # bob
print(combined['color']) # red2.6 Counter
计数器,统计元素出现次数。
from collections import Counter
c = Counter('hello world')
print(c)
print(c['l'])3. argparse —— 命令行参数解析
写命令行工具时,与其手动切 sys.argv,不如用 argparse 自动生成帮助和校验。
import argparse
def main():
parser = argparse.ArgumentParser(
prog='backup',
description='备份 MySQL 数据库'
)
# 位置参数
parser.add_argument('outfile')
# 可选参数
parser.add_argument('--host', default='localhost')
parser.add_argument('--port', default=3306, type=int)
parser.add_argument('-u', '--user', required=True)
parser.add_argument('-p', '--password', required=True)
# 开关参数
parser.add_argument('-gz', '--gzcompress', action='store_true', help='是否压缩')
args = parser.parse_args()
print(f'outfile={args.outfile}')
print(f'host={args.host}')
print(f'user={args.user}')
print(f'gzcompress={args.gzcompress}')
if __name__ == '__main__':
main()运行示例:
python backup.py -u root -p 123456 backup.sql
python backup.py -hargparse 会自动帮你检查必填项、类型转换,并打印 -h 帮助信息。
4. base64 —— 二进制转文本
Base64 是把二进制数据编码成文本字符串的一种方式,常用于 URL、Cookie、邮件里传输少量二进制数据。
import base64
# 编码
origin = b'binary\x00string'
encoded = base64.b64encode(origin)
print(encoded)
# 解码
print(base64.b64decode(encoded))URL 里 + 和 / 会出问题,可以用 url-safe 编码:
import base64
s = b'i\xb7\x1d\xfb\xef\xff'
print(base64.b64encode(s))
print(base64.urlsafe_b64encode(s))
print(base64.urlsafe_b64decode('abcd--__'))Base64 不是加密,只是一种编码。很多场景会把末尾的 = 去掉,解码时自己补回来即可。
5. struct —— 字节和基本类型互转
struct 把整数、浮点数等打包成 bytes,或者反过来解包。
import struct
# 把 4 字节无符号整数打包成 big-endian 字节
b = struct.pack('>I', 10240099)
print(b)
# 解包
print(struct.unpack('>I', b))
# 一次解多个字段
b2 = b'\xf0\xf0\xf0\xf0\x80\x80'
print(struct.unpack('>IH', b2))常用格式字符:
| 字符 | 含义 |
|---|---|
I | 4 字节无符号整数 |
H | 2 字节无符号整数 |
B | 1 字节无符号整数 |
f | 4 字节浮点数 |
d | 8 字节浮点数 |
> | 大端序 |
< | 小端序 |
分析 BMP 文件头时就会用到这个套路。
6. hashlib —— 哈希摘要
哈希算法能把任意长度数据压缩成固定长度的摘要,用来判断数据是否被篡改。
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
# 可以分多次 update
md5_2 = hashlib.md5()
md5_2.update('how to use md5 in '.encode('utf-8'))
md5_2.update('python hashlib?'.encode('utf-8'))
print(md5_2.hexdigest())SHA 系列类似:
import hashlib
sha1 = hashlib.sha1()
sha1.update('hello'.encode('utf-8'))
print(sha1.hexdigest())
sha256 = hashlib.sha256()
sha256.update('hello'.encode('utf-8'))
print(sha256.hexdigest())注意:哈希不是加密,无法从摘要反推原文。密码存储时建议加盐,不要直接存明文或裸 MD5。
7. hmac —— 带密钥的哈希
hmac 是在哈希过程中混入一个 key,相同消息、不同 key 得到不同摘要,常用于接口签名验证。
import hmac
message = b'Hello, world!'
key = b'secret'
h = hmac.new(key, message, digestmod='MD5')
print(h.hexdigest())
# 也可以分段 update
h2 = hmac.new(key, digestmod='sha256')
h2.update(b'Hello, ')
h2.update(b'world!')
print(h2.hexdigest())key 和 message 都要是 bytes 类型。
8. itertools —— 迭代器工具
itertools 提供了一系列方便操作迭代器的函数,返回的大多都是迭代器,不会一次性占用大量内存。
8.1 无限迭代器
import itertools
# 从 1 开始无限计数
for i in itertools.count(1):
if i > 5:
break
print(i)
# 无限循环某个序列
cs = itertools.cycle('AB')
for i, c in enumerate(cs):
if i >= 4:
break
print(c)
# 重复某个元素
for x in itertools.repeat('x', 3):
print(x)8.2 截断无限迭代器
import itertools
natuals = itertools.count(1)
ns = itertools.takewhile(lambda x: x <= 10, natuals)
print(list(ns))8.3 合并与分组
import itertools
# 把多个迭代对象串起来
for c in itertools.chain('ABC', 'XYZ'):
print(c)
# 把相邻重复元素分组
for key, group in itertools.groupby('AAABBBCCAAA'):
print(key, list(group))
# 按自定义规则分组
for key, group in itertools.groupby('AaaBBbcCAAa', lambda c: c.upper()):
print(key, list(group))9. contextlib —— 上下文管理器
with 语句能自动管理资源,例如文件读写。contextlib 让我们可以方便地写出支持 with 的对象。
9.1 自己写上下文管理类
class Query:
def __init__(self, name):
self.name = name
def __enter__(self):
print('Begin')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
print('Error')
else:
print('End')
def query(self):
print(f'Query info about {self.name}')
with Query('Bob') as q:
q.query()9.2 用 @contextmanager 简化
from contextlib import contextmanager
@contextmanager
def create_query(name):
print('Begin')
q = Query(name)
yield q
print('End')
with create_query('Alice') as q:
q.query()9.3 用 closing 把普通对象包进 with
from contextlib import closing
from urllib.request import urlopen
with closing(urlopen('https://www.python.org')) as page:
for line in page:
print(line)
breakclosing 会在 with 结束时调用对象的 close() 方法。
10. urllib —— 网络请求
urllib 是 Python 内置的 HTTP 客户端,可以完成 GET、POST 等请求。
10.1 GET 请求
from urllib import request
with request.urlopen('https://api.github.com') as f:
data = f.read()
print('Status:', f.status, f.reason)
print(data.decode('utf-8'))10.2 添加请求头
from urllib import request
req = request.Request('https://www.douban.com')
req.add_header('User-Agent', 'Mozilla/5.0')
with request.urlopen(req) as f:
print(f.status)
print(f.read().decode('utf-8')[:200])10.3 POST 请求
from urllib import request, parse
login_data = parse.urlencode([
('username', 'test'),
('password', '123456')
]).encode('utf-8')
req = request.Request('https://httpbin.org/post', data=login_data)
req.add_header('User-Agent', 'Mozilla/5.0')
with request.urlopen(req) as f:
print(f.read().decode('utf-8'))10.4 使用代理
import urllib.request
proxy_handler = urllib.request.ProxyHandler({
'http': 'http://proxy.example.com:3128',
'https': 'https://proxy.example.com:3128'
})
opener = urllib.request.build_opener(proxy_handler)
with opener.open('http://example.com') as f:
print(f.status)实际项目里,requests 库更常用,但 urllib 不用额外安装,简单场景完全够用。
11. XML —— SAX 解析
操作 XML 有两种方式:
- DOM:把整个 XML 读进内存,转成树,可以随意遍历,但占内存。
- SAX:流式解析,读一段处理一段,省内存,速度快。
一般优先用 SAX。
from xml.parsers.expat import ParserCreate
class DefaultSaxHandler:
def start_element(self, name, attrs):
print(f'start_element: {name}, attrs: {attrs}')
def end_element(self, name):
print(f'end_element: {name}')
def char_data(self, text):
print(f'char_data: {text}')
xml = r'''<?xml version="1.0"?>
<ol>
<li><a href="/python">Python</a></li>
<li><a href="/ruby">Ruby</a></li>
</ol>
'''
handler = DefaultSaxHandler()
parser = ParserCreate()
parser.StartElementHandler = handler.start_element
parser.EndElementHandler = handler.end_element
parser.CharacterDataHandler = handler.char_data
parser.Parse(xml)生成 XML 最简单的方式就是字符串拼接,复杂结构建议直接用 JSON。
12. HTMLParser —— 解析 HTML
HTML 是 XML 的「不严格」版本,所以要用专门的 HTMLParser。
from html.parser import HTMLParser
from html.entities import name2codepoint
class MyHTMLParser(HTMLParser):
def handle_starttag(self, tag, attrs):
print(f'<{tag}>')
def handle_endtag(self, tag):
print(f'</{tag}>')
def handle_startendtag(self, tag, attrs):
print(f'<{tag}/>')
def handle_data(self, data):
print(data)
def handle_comment(self, data):
print(f'<!--{data}-->')
def handle_entityref(self, name):
print(f'&{name};')
def handle_charref(self, name):
print(f'&#{name};')
parser = MyHTMLParser()
parser.feed('''<html>
<head></head>
<body>
<!-- test html parser -->
<p>Some <a href="#">html</a> HTML tutorial...<br>END</p>
</body></html>''')feed() 可以多次调用,适合流式处理网页内容。
13. venv —— 虚拟环境
不同项目依赖的版本可能冲突,比如 A 项目要 jinja2 2.7,B 项目要 2.6。venv 可以给每个项目一套独立的 Python 环境。
13.1 创建虚拟环境
mkdir myproject
cd myproject
python3 -m venv venv13.2 激活
Linux / macOS:
source venv/bin/activateWindows:
venv\Scripts\activate.bat激活后命令行前面会出现 (venv) 提示。
13.3 安装依赖
pip install requests安装好的包会放在 venv/lib/python3.x/site-packages 下,不影响系统 Python。
13.4 退出
deactivate13.5 删除
rm -rf venv本章小结
本章过了一遍 Python 里 13 个常用内建模块:
datetime:日期时间获取、转换、格式化、时区处理。collections:namedtuple、deque、defaultdict、OrderedDict、ChainMap、Counter等增强集合。argparse:命令行参数解析和自动生成帮助。base64:二进制数据转文本编码。struct:字节和基本数据类型打包/解包。hashlib:MD5、SHA 等哈希摘要。hmac:带密钥的哈希,用于签名验证。itertools:无限/有限迭代器、合并、分组等工具。contextlib:用@contextmanager和closing简化with语句。urllib:内置 HTTP 请求,GET/POST/代理都能做。xml:SAX 方式解析 XML。HTMLParser:解析不严格的 HTML 页面。venv:项目隔离的 Python 环境,避免依赖冲突。
这些模块不需要全部背下来,重点是知道它们能解决什么问题,用的时候再查官方文档即可。Python 内置库丰富,就是生产力。