Python 现代开发学习笔记

(十六)处理常见任务的标准库

1. Counter 统计次数

第二章用 counts[title] = counts.get(title, 0) + 1 逐项统计。collections.Counter 把这项工作封装好了:

# Counter 读取书名,按同名次数建立计数;没有出现的键读作 0。
from collections import Counter

counts = Counter(["Python", "NumPy", "Python", "Pygame"])
print(counts["Python"], counts["Django"])
print(counts.most_common(2))
# 需要指定同次数的顺序时,继续用明确的排序键。
print(sorted(counts.items(), key=lambda item: (-item[1], item[0])))

得到 2 0、[('Python', 2), ('NumPy', 1)],以及 [('Python', 2), ('NumPy', 1), ('Pygame', 1)]。most_common(2) 按次数取前两项,同次数按首次出现顺序排列;最后的排序则明确要求同次数按名称升序。

2. defaultdict 为新键建立分组

# 传入 list 这个可调用对象,首次用 [] 访问新键时由它创建空列表。
from collections import defaultdict

groups = defaultdict(list)
for title, minutes in [("Python", 20), ("NumPy", 35), ("Python", 45)]:
    groups[title].append(minutes)
print(dict(groups))

得到 {'Python': [20, 45], 'NumPy': [35]}。第一次读取 groups["Python"] 时,defaultdict 调用 list(),把新列表放进该键,再追加 20。传入的是 list,写成 list() 会先得到列表对象,而这里需要一个能被调用的默认工厂。

这种自动建立发生在下标读取 groups[key] 中;groups.get(key) 仍遵循普通字典的读取方式,不会为缺失键调用工厂。要合并所有同名记录,用字典式分组;要分开连续的同名片段,用前面的 groupby。

3. deque 从两端处理数据

# deque 支持在两端加入与取出,这里按加入顺序处理任务。
from collections import deque

tasks = deque(["整理语法", "完成练习"])
tasks.append("复盘错误")
print(tasks.popleft())
print(list(tasks))
# maxlen=3 保留最近三项,满后从另一端移除旧项。
recent = deque([20, 35, 45], maxlen=3)
recent.append(10)
print(list(recent))

输出“整理语法”、['完成练习', '复盘错误']、[35, 45, 10]。列表从头删除需要移动后面的引用;双端队列将两端加入、取出的常见工作量保持为 O(1)O(1),适合排队处理和保留近期记录。随机读取中间位置时,它与列表按下标访问的成本不同。collections 容器工具

4. datetime 处理日期、时间与时区

# date 表示日历日期,timedelta 表示时间间隔。
from datetime import date, timedelta

started = date.fromisoformat("2026-10-19")
deadline = started + timedelta(days=7)
print(deadline.isoformat())
print((deadline - started).days)
# total_seconds 计算完整间隔;seconds 只是扣除整天后的秒数部分。
gap = timedelta(days=1, minutes=5)
print(gap.total_seconds(), gap.seconds)

输出 2026-10-26、7、86700.0 300。fromisoformat 从 ISO 格式字符串建立日期对象,isoformat 转回这种格式。直接用日期运算,不需要自己按月份拆算天数。

记录一个具体时刻时,还要带上时区信息:

# 输入中的 +08:00 表示比 UTC 快八小时;转换后仍表示同一时刻。
from datetime import datetime, timezone

local = datetime.fromisoformat("2026-10-19T08:30:00+08:00")
utc_time = local.astimezone(timezone.utc)
print(local.isoformat())
print(utc_time.isoformat())

分别输出 2026-10-19T08:30:00+08:00 和 2026-10-19T00:30:00+00:00。datetime 同时保存日期与时间,timezone.utc 提供 UTC 时区,astimezone 换一种时区表示相同时刻。带时区信息的值称为 aware datetime;没有时区信息的值称为 naive datetime。把两者直接相减会报错,因为后者没有说明时间属于哪一个时区。日期与时间

5. re 提取和检查有结构的文本

数据行采用 书名:分钟数 的形式时,第二章的 split 已经能完成简单切分。若还需要检查分钟部分全是数字,可以用正则表达式描述字符结构:

# compile 把模式建立成可复用对象;fullmatch 要求整行符合模式。
import re

pattern = re.compile(r"(.+):([0-9]+)")
for line in ["Python 入门:45", "Python 入门:很多"]:
    matched = pattern.fullmatch(line)
    if matched is None:
        print("记录格式错误")
        continue
    # 两对圆括号保存两个分组,分别取出书名和数字文本。
    title = matched.group(1)
    minutes = int(matched.group(2))
    print(title, minutes)

# findall 查找所有数字片段,sub 将连续空白统一替换为一个空格。
print(re.findall(r"[0-9]+", "阅读20分钟,休息5分钟"))
print(re.sub(r"\s+", " ", "Python   入门"))

输出“Python 入门 45”“记录格式错误”、['20', '5'] 和“Python 入门”。r"..." 是原始字符串写法,反斜杠由正则规则解释,例如 r"\s" 表示正则中的空白字符类;原始字符串并不会关闭正则本身的特殊符号。

模式片段或操作 本例中的动作
.、+ 匹配换行以外的字符,并重复一次或多次
[0-9]+ 取得一串 ASCII 数字
(...) 保存可以通过 group 取回的分组
\s+ 匹配连续空白
fullmatch 整段文本必须符合模式
search、findall 在文本中查找首个匹配,或取得全部匹配结果

这里的“整行匹配成功”先给出匹配对象,matched is None 则表示没有找到。访问分组前先处理未匹配的情况。HTML、JSON 这样的格式还有自己的结构与解析器,爬虫和文件章节会用对应工具读取。正则表达式

笔记正文与全部题解 · Ctrl / ⌘ K