08 · 常用模块(Standard Library)

📅 预计 60 分钟 | ⭐ 按考点掌握即可
✍️ 本讲配套练习:本地 python grader.py 08,或网页练习


Python 自带一套「家用工具箱」,import 就能用,这就是标准库。前面学的 printlen 是内置功能;今天的 mathrandomjsondatetimerecollections 是工具箱里的常备工具。原则:别人造好的轮子别自己造。本讲 15 题,建议学一节练对应题。

8.1 导入方式

import 像从抽屉里拿工具,三种拿法:

import math                 # 整盒拿:用 math.sqrt(16)
from os import path         # 只拿一件:直接 path.join(...)
import random as r          # 起小名:r.randint(1, 100)

from collections import Counter 最常用——只拿要用的,代码更短。但注意命名冲突:自己定义了 sqrtfrom math import sqrt,后者覆盖前者,全名导入最稳。

⚠️ 常见错误:import 时机
import 放文件顶部集中管理。别在函数内部 import——虽合法但每次调用重复加载。

8.2 math —— 随身计算器

math 就是计算器。** 能做乘方,但开方、取整、三角函数还得靠它:

import math
math.sqrt(16)          # 开平方 → 4.0(结果一定是 float)
math.pow(2, 10)        # 2 的 10 次方 → 1024.0
math.ceil(3.2)         # 向上取整 → 4(ceil 天花板)
math.floor(3.7)        # 向下取整 → 3(floor 地板)
math.hypot(3, 4)       # 直角边 3、4 的斜边 → 5.0
math.pi, math.e        # 圆周率、自然常数

ceil/floor 就是天花板/地板:快递费 2.01 按 3 元收是 ceil,跑 2.9 公里按 2 公里算是 floor

练习: ex01(圆面积)、ex07(斜边)。

⚠️ 常见错误:float 干扰显示
sqrt 返回 float,f"{math.sqrt(16)}" 得到 4.0。判分对 float 有容差,展示时记得 round。

8.3 random —— 抽签盒

random 是抽签盒,做游戏、抽样都靠它。核心记住:它是伪随机——由种子(seed)决定,同一种子结果一样,因此可复现。

import random
random.random()               # [0,1) 浮点数
random.randint(1, 100)        # 1~100 整数,含两端 ⭐
random.choice(["a","b","c"])  # 随机抽一个
random.sample(range(100), 5)  # 不重复抽 5 个
random.shuffle(lst)           # 原地打乱(返回 None!)
random.seed(2026)             # 固定种子,之后结果可复现
random.randint(1, 6)          # 每次跑都一样

测试、判分时固定 seed 就能得到稳定输出。

练习: ex06(掷骰子,判分靠固定 seed)。

⚠️ 常见错误:随机不可测、shuffle 返回 None
① 随机输出不可预测,别写依赖随机结果的测试(除非固定 seed)。② shuffle 原地修改并返回 Nonelst = random.shuffle(lst) 会把列表变成 None。③ 不重复抽用 sample,允许重复用 choices

8.4 datetime —— 日历与闹钟

datetime 管时间。两个核心操作:格式化(时间变字符串)和解析(字符串变时间)。

from datetime import datetime, timedelta

now = datetime.now()                       # 当前时间
now.strftime("%Y-%m-%d %H:%M:%S")          # → '2026-08-02 09:50:00' ⭐
d = datetime(2027, 12, 25)                 # 构造具体时间
diff = d - now                             # 时间差 timedelta
diff.days                                  # 相差天数

格式串常见符:%Y 四位年、%m 月、%d 日、%H 时、%M 分、%S 秒。大小写敏感%Y(年) vs %y(两位年)、%m(月) vs %M(分)。

t = datetime.strptime("2027-12-25", "%Y-%m-%d")   # 字符串→时间 ⭐
s = now.strftime("%Y年%m月%d日")                   # 时间→字符串 '2026年08月02日'

口诀:strptime 是 p 进 str 出,strftime 是 f 出 strnow + timedelta(days=7) 就是下周。

练习: ex04(日期差)。

⚠️ 常见错误:格式串大小写、strptime 严格匹配
%m 是月、%M 是分钟,写错不报错但结果错。② strptime 要求字符串和格式串严格一致,多空格或 0 就 ValueError。③ 别把参数顺序记反,格式串永远在前。

8.5 collections —— 工具箱的升级配件

① Counter —— 计数器,统计次数一行顶十行:

from collections import Counter
c = Counter(["a","b","a","c","a","b"])   # Counter({'a': 3, 'b': 2, 'c': 1})
c.most_common(1)                         # [('a', 3)] ⭐

② defaultdict —— 带默认值的字典。普通字典访问不存在的键会 KeyError,它有"初始装备":

from collections import defaultdict
c = defaultdict(int)                     # 默认值 0
for ch in "hello":
    c[ch] += 1                           # 键不存在也敢直接加
print(dict(c))                           # {'h': 1, 'e': 1, 'l': 2, 'o': 1}

defaultdict(list) 默认空列表,defaultdict(set) 默认空集合。

③ namedtuple —— 带名字的元组。普通元组 (3,4) 只能 p[0]p[1],命名元组能用名字取:

from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
p.x, p.y                                 # 3 4,比 p[0] 好读

仍是元组不可修改,适合坐标、成绩这类固定几项的数据。

④ deque —— 双端队列,两头快速进出,还有轮转 rotate

from collections import deque
d = deque([1, 2, 3, 4, 5])
d.rotate(-2)                             # 整体左移 2 位
print(list(d))                           # [3, 4, 5, 1, 2] ⭐

rotate(2) 右移、rotate(-2) 左移。轮播、循环队列一行搞定。

练习: ex03(Counter)、ex09(defaultdict)、ex10(deque.rotate)、ex11(namedtuple)、ex15(defaultdict+排序)。

⚠️ 常见错误:defaultdict 传工厂函数、namedtuple 不可改
defaultdict(int)工厂函数(不带括号),写 defaultdict(0)TypeError。② namedtuple 不可变,p.x = 5AttributeError,要改就重建。③ Counter 是字典子类,能比较、能加减。

8.6 json —— 快递打包与拆包

json 是程序间交换数据的标准快递箱。JSON 文本长得像 Python 字典,但它是纯字符串

  • 打包(Python → JSON 字符串):json.dumps
  • 拆包(JSON 字符串 → Python):json.loads
import json
data = json.loads('{"title": "哪吒", "rate": 9.0}')   # → {'title': '哪吒', 'rate': 9.0}
s = json.dumps({'name': '哪吒', 'rate': 9.0}, ensure_ascii=False)
print(s)                            # → {"name": "哪吒", "rate": 9.0}

默认 json.dumps 会把中文转成 \uXXXX,写中文应用务必加 ensure_ascii=False

练习: ex02(loads)、ex08(dumps)。

⚠️ 常见错误:中文变 \uXXXX、类型不支持
① 忘了 ensure_ascii=False,中文全变 \uXXXX。② JSON 只支持基本类型,setdatetime 直接 dumps 会 TypeError。③ loads 格式不合法抛 JSONDecodeError,解析外部数据要 try。

8.7 re —— 找规律

re 是"找规律"的终极工具:写一个模式,让程序按模式匹配文本,就像在电话簿里搜"所有 138 开头的 11 位号码"。

常用元字符:

元字符 含义 例子
\d 一个数字 a1b 匹配 1
\w 字母/数字/下划线 a_1
\s 空白 空格/Tab
. 任意一个字符 a.c 匹配 abc
* 前一个出现 0 次或多次 a* 匹配空/a/aaa
+ 前一个出现 1 次或多次 a+ 不匹配空
? 前一个出现 0 次或 1 次 colou?r
{2,4} 前一个出现 2~4 次 \d{11}
^ $ 开头 / 结尾 ^abcxyz$
[a-z] 字符集任一个 [0-9] 等价 \d
import re
re.findall(r"\d+", "a1b22c333")     # ['1', '22', '333'] 找所有 ⭐
re.search(r"\d+", "abc123")         # 找第一个,返回 match 对象
re.match(r"\d+", "123abc")          # 只匹配开头,开头不是数字则 None
re.sub(r"\d", "#", "a1b2")          # 替换 → 'a#b#'

分工:findall 找全部返回列表、search 找第一个、match 只匹配开头、sub 替换。字符串前加 r(原始字符串),否则 \d 被当转义符。

分组提取——括号圈出要留的部分:

m = re.search(r"(\w+)@\w+\.\w+", "contact: tom@example.com")
m.group(1)                          # 'tom' ⭐

手机号验证——fullmatch 要求整串匹配:

re.fullmatch(r"1\d{10}", "13812345678")   # 非 None 即合法

替换打码——保留前 3 后 4:

re.sub(r"(1\d{2})\d{4}(\d{4})", r"\1****\2", "联系 13812345678 尽快")
# → '联系 138****5678 尽快'

\1\2 在替换串里引用第 1、2 分组。

练习: ex05(findall)、ex12(sub+分组)、ex15(findall)。

⚠️ 常见错误:贪婪、忘 r、group 索引
① 正则默认贪婪r"a.*c" 匹配 a...c...c 会吞到最后一个 c,想要最短用非贪婪 r"a.*?c"。② 忘了 r 前缀,\d 报错。③ search 返回 None 时调 group(1) 会崩,先 if m:。④ 分组从 1 编号,group(0) 是整体。

8.8 os.path / sys / time / hashlib —— 系统与文件

① os.path —— 路径小助手。拼、拆、查路径,跨平台自动适配分隔符:

import os
os.path.join("data", "report.txt")     # 'data/report.txt' ⭐
os.path.exists("a.txt")                # 是否存在
os.path.isfile("a.txt")                # 是否文件
os.path.basename("data/report.txt")    # 'report.txt' ⭐
os.path.splitext("report.txt")         # ('report', '.txt') ⭐
os.path.dirname("data/report.txt")     # 'data'

② sys —— 命令行参数argv[0] 是程序文件名,argv[1:] 才是参数:

import sys
# 命令行:python my.py 2026 08 02
sys.argv                    # ['my.py', '2026', '08', '02'],全是字符串!

要用数字先 int() 转换。

③ time —— 时间戳time.time() 返回 1970 年 1 月 1 日至今的秒数,用来计时:

import time
time.strftime("%Y-%m-%d", time.gmtime(0))       # '1970-01-01' ⭐
time.strftime("%Y-%m-%d", time.gmtime(86400))   # '1970-01-02'

gmtime(UTC)避免本地时区干扰。

④ hashlib —— 哈希指纹。文本算成一串固定长度"指纹",同样输入永远同样输出,几乎无法反推,常用于存密码:

import hashlib
hashlib.sha256("hello".encode()).hexdigest()
# 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

sha256()字节,字符串要先 .encode()

练习: ex13(os.path)、ex14(hashlib)、ex15(综合,sys.argv)。

⚠️ 常见错误:路径拼接、argv 索引、hashlib 忘 encode
① 手写 "data/" + "report.txt" 在 Windows 会出问题,永远用 os.path.join。② sys.argv 从 0 开始且全是字符串,没传参访问 argv[1] 索引越界。③ sha256("hello")TypeError,必须 .encode()。④ time.localtime 依赖时区,判分验证用 gmtime 更稳。


💡 记忆口诀

  • strptime p 进 str 出,strftime f 出 str
  • \d 数字、\w 字母、+ 一个以上
  • dumps 出字符串、loads 进字典
  • defaultdict(int) 传工厂函数不带括号
  • shuffle 原地改返回 None

📌 双语术语表(本讲)

中文 English
模块 module
导入 import
标准库 standard library
正则表达式 regular expression
时间戳 timestamp
计数 counter
随机数 random number
序列化 serialize
哈希 hash
双端队列 deque

⭐ 本讲考点清单

  1. os.path.join / exists / basename / splitext
  2. 正则 \d+findall / search / sub、分组与 \1 引用、fullmatch 手机号验证
  3. random.randint / choice / sample / shuffleseed 复现
  4. datetime.now() + strftime / strptimetimedelta 日期差
  5. Counter.most_commondefaultdictnamedtupledeque.rotate
  6. math.sqrt / floor / ceil / pow
  7. json.loads / dumps(ensure_ascii=False)
  8. sys.argvhashlib.sha256time.gmtime / strftime