八、标准库核心模块(按功能分类)

阶段定位:Python 的强大不仅在于语法,更在于丰富的标准库。”batteries included”意味着你不需要为常见任务去安装第三方包。本阶段按功能分类梳理核心标准库,帮你建立”标准库优先”的工程思维。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
┌──────────────────────────────────────────────────────────────────┐
│ Python 标准库知识图谱 │
├──────────────────────────────────────────────────────────────────┤
│ │
│ 文本处理 │
│ ├── re(正则表达式) │
│ ├── string(字符串常量) │
│ └── textwrap(文本格式化) │
│ │
│ 数据结构 │
│ ├── collections(namedtuple/deque/Counter/defaultdict等) │
│ ├── heapq(堆队列) │
│ └── bisect(二分查找) │
│ │
│ 函数式工具 │
│ ├── functools(partial/reduce/lru_cache/wraps) │
│ ├── itertools(无限迭代/组合生成/分组) │
│ └── operator(操作符函数化) │
│ │
│ 文件与路径 │
│ ├── os(操作系统接口) │
│ ├── os.path(路径操作) │
│ ├── pathlib(面向对象路径) │
│ └── shutil(高级文件操作) │
│ │
│ 网络与通信 │
│ ├── urllib(HTTP客户端) │
│ ├── socket(网络编程) │
│ └── http(HTTP协议) │
│ │
│ 并发与异步 │
│ ├── threading(线程) │
│ ├── multiprocessing(进程) │
│ ├── concurrent.futures(并发接口) │
│ └── asyncio(异步IO) │
│ │
│ 数据持久化 │
│ ├── json(JSON序列化) │
│ ├── pickle(对象序列化) │
│ └── sqlite3(SQLite数据库) │
│ │
│ 时间与日期 │
│ ├── datetime(日期时间处理) │
│ ├── time(时间基础) │
│ └── calendar(日历操作) │
│ │
│ 其他工具 │
│ ├── logging(日志) │
│ ├── argparse(命令行参数) │
│ ├── configparser(配置文件) │
│ └── hashlib(哈希算法) │
│ │
└──────────────────────────────────────────────────────────────────┘

1. 文本与字符串

1.1 re 正则表达式

正则表达式是处理文本的利器,用于模式匹配、查找、替换和分割。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import re

# 基础匹配
text = "Email: alice@example.com, Phone: 138-1234-5678"

# search:查找第一个匹配
match = re.search(r"\w+@\w+\.\w+", text)
if match:
print(match.group()) # alice@example.com
print(match.span()) # (7, 24)

# findall:查找所有匹配
emails = re.findall(r"\w+@\w+\.\w+", text)
phones = re.findall(r"\d{3}-\d{4}-\d{4}", text)

# finditer:返回迭代器(节省内存)
for match in re.finditer(r"\d+", text):
print(f"数字: {match.group()}, 位置: {match.span()}")

# sub:替换
redacted = re.sub(r"\w+@\w+\.\w+", "[EMAIL]", text)

# split:按模式分割
parts = re.split(r"[,;]\s*", "a, b; c, d")

# 编译正则(频繁使用时提升性能)
EMAIL_PATTERN = re.compile(r"^[\w.-]+@[\w.-]+\.\w+$")
print(EMAIL_PATTERN.match("test@example.com")) # Match
print(EMAIL_PATTERN.match("invalid")) # None

# 命名捕获组
pattern = re.compile(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})")
match = pattern.match("2024-07-20")
print(match.groupdict()) # {'year': '2024', 'month': '07', 'day': '20'}

常用正则模式速查

模式 含义
. 任意字符(除换行)
\d 数字 [0-9]
\w 单词字符 [a-zA-Z0-9_]
\s 空白字符
* 0 次或多次
+ 1 次或多次
? 0 次或 1 次
{n,m} n 到 m 次
^ / $ 字符串开头/结尾
() 捕获组
(?:...) 非捕获组
(?P<name>...) 命名捕获组
\b 单词边界

正则表达式工作流程

1
2
3
4
5
6
文本输入 → 正则模式 → 匹配引擎 → 匹配结果/None
│ │ │
│ └→ 编译正则 │
│ │
└───────────────────────┘
重复使用

工程实践建议

  1. 复杂正则使用 re.compile() 编译后复用,提升性能
  2. 使用命名捕获组 (?P<name>...) 让代码更易读
  3. 正则表达式调试困难,尽量保持简洁
  4. 对于简单模式,优先使用字符串方法(str.startswith(), str.find() 等)

1.2 stringtextwrap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import string
import textwrap

# string 常量
print(string.ascii_letters) # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
print(string.digits) # 0123456789
print(string.punctuation) # !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

# textwrap:文本格式化
long_text = "这是一个非常长的段落,需要自动换行和缩进处理。"

# 自动换行
wrapped = textwrap.fill(long_text, width=20)
print(wrapped)

# 添加缩进
indented = textwrap.indent(long_text, " ")
print(indented)

# 去除缩进
dedented = textwrap.dedent("""
第一行
第二行
第三行
""")

# 截断文本
truncated = textwrap.shorten("这是一段很长的文本需要截断显示。", width=20)

应用场景

  • string.digits + string.ascii_letters:生成验证码
  • textwrap.fill():格式化日志输出
  • textwrap.dedent():去除多行字符串的公共缩进

2. 数据结构增强

2.1 collections

collections 模块提供了高性能的容器类型,是对内置数据结构的扩展。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from collections import namedtuple, deque, Counter, OrderedDict, defaultdict, ChainMap

# namedtuple:轻量级不可变对象
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y) # 3 4
print(p._asdict()) # {'x': 3, 'y': 4}

# deque:双端队列(两端操作都是 O(1))
dq = deque([1, 2, 3])
dq.append(4) # 右端添加
dq.appendleft(0) # 左端添加
dq.pop() # 右端弹出
dq.popleft() # 左端弹出
dq.rotate(1) # 旋转

# Counter:计数器
c = Counter(["a", "b", "a", "c", "a", "b"])
print(c) # Counter({'a': 3, 'b': 2, 'c': 1})
print(c.most_common(2)) # [('a', 3), ('b', 2)]

# 统计字符频率
char_count = Counter("mississippi")
print(char_count.most_common(3))

# defaultdict:带默认值的字典
word_groups = defaultdict(list)
for word in ["apple", "apricot", "banana", "blueberry"]:
word_groups[word[0]].append(word)
print(dict(word_groups)) # {'a': ['apple', 'apricot'], 'b': ['banana', 'blueberry']}

# OrderedDict:有序字典(3.7+ 普通 dict 已有序,但 OrderedDict 有特殊方法)
od = OrderedDict([("a", 1), ("b", 2)])
od.move_to_end("a") # 将 a 移到最后

# ChainMap:链式字典查找(不合并,只链接)
defaults = {"theme": "default", "language": "en"}
user_prefs = {"theme": "dark"}
combined = ChainMap(user_prefs, defaults)
print(combined["theme"]) # dark(从 user_prefs 找到)
print(combined["language"]) # en(从 defaults 找到)

collections 各类型对比

类型 特点 适用场景
namedtuple 不可变,字段可通过属性访问 轻量级数据结构、记录
deque 双端 O(1) 操作 队列、栈、滑动窗口
Counter 自动计数 词频统计、投票计数
defaultdict 访问不存在键自动创建默认值 分组聚合
OrderedDict 保持插入顺序,支持移动 LRU 缓存、有序配置
ChainMap 链式查找,不复制 配置优先级、多字典合并

2.2 heapq 堆队列

堆是一种特殊的树形数据结构,最小堆的堆顶元素始终是最小的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import heapq

# 堆(最小堆):快速获取最小/最大元素
nums = [5, 2, 8, 1, 9, 3]
heapq.heapify(nums) # 原地转堆,O(n)
print(heapq.heappop(nums)) # 1(最小元素)
heapq.heappush(nums, 0) # 添加元素,O(log n)

# 获取最大的 N 个元素(比排序后切片快)
largest = heapq.nlargest(3, [5, 2, 8, 1, 9, 3])
smallest = heapq.nsmallest(3, [5, 2, 8, 1, 9, 3])

# 实现优先队列
class PriorityQueue:
def __init__(self):
self._queue = []
self._index = 0

def push(self, item, priority):
# (priority, index, item) 保证相同优先级按插入顺序排列
heapq.heappush(self._queue, (priority, self._index, item))
self._index += 1

def pop(self):
return heapq.heappop(self._queue)[-1]

# 使用优先队列
pq = PriorityQueue()
pq.push("task1", 2)
pq.push("task2", 1)
pq.push("task3", 1)
print(pq.pop()) # task2(优先级最高)
print(pq.pop()) # task3(同优先级,先插入的先出)

堆操作时间复杂度

操作 时间复杂度
heapify() O(n)
heappush() O(log n)
heappop() O(log n)
nlargest(n) O(n log n)
nsmallest(n) O(n log n)

应用场景

  • 任务调度(优先队列)
  • Top-K 问题(获取最大/最小的 N 个元素)
  • 数据流中位数

2.3 bisect 二分查找

bisect 模块提供了在有序列表中进行二分查找和插入的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import bisect

# 维护有序列表
sorted_list = [1, 3, 5, 7, 9]

# 查找插入位置
pos = bisect.bisect_left(sorted_list, 6) # 3(在 5 后面)
pos = bisect.bisect_right(sorted_list, 5) # 3(在 5 后面)

# 插入并保持有序
bisect.insort(sorted_list, 6) # [1, 3, 5, 6, 7, 9]

# 查找元素是否存在
idx = bisect.bisect_left(sorted_list, 7)
if idx < len(sorted_list) and sorted_list[idx] == 7:
print("找到 7")

# 二分查找实现
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1

bisect 函数对比

函数 行为 返回值含义
bisect_left() 查找第一个大于等于 target 的位置 插入位置(左侧)
bisect_right() 查找第一个大于 target 的位置 插入位置(右侧)
insort_left() 在 bisect_left 位置插入
insort_right() 在 bisect_right 位置插入

应用场景

  • 维护有序数据结构
  • 区间查询
  • 时间序列数据查找

3. 函数式工具

3.1 functools

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from functools import partial, reduce, lru_cache, wraps, cmp_to_key, total_ordering

# partial:固定部分参数
base_two = partial(int, base=2)
print(base_two("1010")) # 10

# lru_cache:最近最少使用缓存
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)

# total_ordering:自动生成比较方法
@total_ordering
class Version:
def __init__(self, major, minor, patch):
self.version = (major, minor, patch)
def __eq__(self, other):
return self.version == other.version
def __lt__(self, other):
return self.version < other.version

# cmp_to_key:将比较函数转为 key 函数
def compare_length(a, b):
return len(a) - len(b)

words = ["apple", "pie", "banana"]
words.sort(key=cmp_to_key(compare_length))

# wraps:保留原函数元信息
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Before")
result = func(*args, **kwargs)
print("After")
return result
return wrapper

functools 常用工具对比

工具 作用 场景
partial 固定函数部分参数 简化函数调用
reduce 累积操作 归约计算(求和、乘积等)
lru_cache 函数结果缓存 避免重复计算
wraps 保留函数元信息 装饰器中使用
cmp_to_key 比较函数转 key 自定义排序
total_ordering 自动生成比较方法 类定义

3.2 itertools

itertools 提供了高效的循环工具,用于创建各种迭代器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import itertools

# 无限迭代器
count = itertools.count(start=10, step=2) # 10, 12, 14, ...
cycle = itertools.cycle(["A", "B", "C"]) # A, B, C, A, B, C, ...
repeat = itertools.repeat("X", 5) # X, X, X, X, X

# 组合生成器
items = ["A", "B", "C"]
print(list(itertools.permutations(items, 2))) # 排列:AB, AC, BA, BC, CA, CB
print(list(itertools.combinations(items, 2))) # 组合:AB, AC, BC
print(list(itertools.combinations_with_replacement(items, 2)))

# 累积
cumulative = list(itertools.accumulate([1, 2, 3, 4, 5])) # [1, 3, 6, 10, 15]

# 分组(注意:需要先排序)
data = [("A", 1), ("A", 2), ("B", 3), ("B", 4)]
sorted_data = sorted(data, key=lambda x: x[0])
for key, group in itertools.groupby(sorted_data, key=lambda x: x[0]):
print(key, list(group))

# 链式迭代
combined = itertools.chain([1, 2], [3, 4], [5, 6])
print(list(combined)) # [1, 2, 3, 4, 5, 6]

# zip_longest:不等长序列
names = ["Alice", "Bob"]
ages = [30, 25, 35]
for name, age in itertools.zip_longest(names, ages, fillvalue="N/A"):
print(name, age)

# islice:切片迭代器
nums = iter(range(10))
sliced = itertools.islice(nums, 2, 8, 2) # 2, 4, 6

# tee:复制迭代器
it1, it2 = itertools.tee(range(5))
print(list(it1)) # [0, 1, 2, 3, 4]
print(list(it2)) # [0, 1, 2, 3, 4]

itertools 分类速查

类别 函数 功能
无限迭代 count, cycle, repeat 生成无限序列
终止迭代 accumulate, chain, islice, tee 处理有限序列
组合生成 permutations, combinations, product 排列组合
分组筛选 groupby, filterfalse, compress 分组和过滤

3.3 operator

operator 模块提供了Python内置操作符的函数化版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from operator import itemgetter, attrgetter, methodcaller, add, mul, lt, eq

# itemgetter:用于排序和取值
data = [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]
sorted_data = sorted(data, key=itemgetter("age"))

# 多个键排序
sorted_by_age_name = sorted(data, key=itemgetter("age", "name"))

# 批量取值
get_name = itemgetter("name")
print(list(map(get_name, data))) # ['Alice', 'Bob']

# attrgetter:获取对象属性
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

people = [Person("Alice", 30), Person("Bob", 25)]
sorted_people = sorted(people, key=attrgetter("age"))

# methodcaller:调用方法
upper = methodcaller("upper")
print(upper("hello")) # HELLO

# 指定参数调用
replace = methodcaller("replace", "l", "x")
print(replace("hello")) # hexlo

# 算术操作符
print(add(3, 5)) # 8
print(mul(3, 5)) # 15
print(lt(3, 5)) # True

operator 常用函数

类别 函数 对应操作
算术 add, sub, mul, truediv, floordiv +, -, *, /, //
比较 eq, ne, lt, le, gt, ge ==, !=, <, <=, >, >=
逻辑 not_, truth, is_, is_not not, bool(), is, is not
序列 itemgetter, attrgetter, methodcaller 索引、属性、方法调用

4. 文件与路径

4.1 os 模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import os

# 目录操作
print(os.getcwd()) # 获取当前工作目录
os.chdir("/path/to/dir") # 切换目录
os.makedirs("dir/subdir", exist_ok=True) # 创建多级目录
os.rmdir("empty_dir") # 删除空目录

# 文件操作
os.rename("old.txt", "new.txt")
os.remove("file.txt")

# 路径操作(建议使用 pathlib)
os.path.join("dir", "file.txt")
os.path.abspath("relative/path")
os.path.exists("path/to/file")
os.path.isfile("file.txt")
os.path.isdir("dir")
os.path.getsize("file.txt")

# 环境变量
print(os.environ.get("PATH"))
os.environ["MY_VAR"] = "value"

# 执行命令
result = os.system("ls -l")

# 遍历目录
for root, dirs, files in os.walk("directory"):
for file in files:
print(os.path.join(root, file))

4.2 pathlib(面向对象路径)

Python 3.4+ 引入的面向对象路径处理方式,比 os.path 更优雅。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pathlib import Path

# 创建路径对象
p = Path("docs") / "guide" / "readme.txt"
print(p) # docs/guide/readme.txt
print(p.resolve()) # 绝对路径
print(p.exists()) # 是否存在
print(p.is_file()) # 是否是文件
print(p.is_dir()) # 是否是目录

# 获取路径信息
print(p.name) # readme.txt
print(p.stem) # readme
print(p.suffix) # .txt
print(p.parent) # docs/guide
print(p.parents[0]) # docs/guide

# 创建目录
p.mkdir(parents=True, exist_ok=True)

# 读取文件(推荐使用 with 语句)
content = p.read_text(encoding="utf-8")

# 写入文件
p.write_text("Hello, World!", encoding="utf-8")

# 遍历目录
for item in Path(".").glob("**/*.py"):
print(item)

# 路径比较
p1 = Path("docs/readme.txt")
p2 = Path("docs") / "readme.txt"
print(p1 == p2) # True

pathlib vs os.path

操作 os.path pathlib
连接路径 os.path.join(a, b) a / b
绝对路径 os.path.abspath(p) p.resolve()
判断存在 os.path.exists(p) p.exists()
读取文本 open(p).read() p.read_text()
写入文本 open(p, 'w').write() p.write_text()

4.3 shutil(高级文件操作)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import shutil

# 复制文件
shutil.copy("src.txt", "dst.txt")
shutil.copy2("src.txt", "dst.txt") # 保留元数据

# 复制目录(递归)
shutil.copytree("src_dir", "dst_dir", dirs_exist_ok=True)

# 移动文件/目录
shutil.move("src", "dst")

# 删除目录(递归)
shutil.rmtree("dir_to_delete")

# 文件压缩
shutil.make_archive("archive", "zip", "source_dir")

# 文件解压
shutil.unpack_archive("archive.zip", "target_dir")

# 获取磁盘使用情况
disk_usage = shutil.disk_usage("/")
print(f"总空间: {disk_usage.total / 1e9:.2f} GB")
print(f"已使用: {disk_usage.used / 1e9:.2f} GB")
print(f"可用空间: {disk_usage.free / 1e9:.2f} GB")

5. 网络与通信

5.1 urllib(HTTP 客户端)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from urllib import request, parse, error

# 发送 GET 请求
response = request.urlopen("https://api.example.com/data")
data = response.read().decode("utf-8")

# 发送 POST 请求
data = {"key": "value"}
encoded_data = parse.urlencode(data).encode("utf-8")
response = request.urlopen("https://api.example.com/submit", data=encoded_data)

# 设置请求头
headers = {"User-Agent": "Mozilla/5.0"}
req = request.Request("https://example.com", headers=headers)
response = request.urlopen(req)

# 处理异常
try:
response = request.urlopen("https://nonexistent.example.com")
except error.HTTPError as e:
print(f"HTTP Error: {e.code}")
except error.URLError as e:
print(f"URL Error: {e.reason}")

# 下载文件
request.urlretrieve("https://example.com/image.jpg", "local_image.jpg")

5.2 http.server(内置 Web 服务器)

1
2
3
4
5
6
7
8
9
10
11
12
import http.server
import socketserver

# 启动简单 HTTP 服务器
PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler

with socketserver.TCPServer(("", PORT), Handler) as httpd:
print(f"Serving at port {PORT}")
httpd.serve_forever()

# 命令行方式:python -m http.server 8000

6. 并发与异步

6.1 threading(线程)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import threading
import time

def worker(name, delay):
for i in range(5):
print(f"{name}: {i}")
time.sleep(delay)

# 创建线程
t1 = threading.Thread(target=worker, args=("Thread-1", 0.5))
t2 = threading.Thread(target=worker, args=("Thread-2", 0.5))

# 启动线程
t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()

# 线程锁(防止竞态条件)
lock = threading.Lock()
shared_counter = 0

def increment():
global shared_counter
with lock:
shared_counter += 1

# 线程本地存储
local_data = threading.local()
local_data.user_id = "123"

6.2 multiprocessing(进程)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import multiprocessing

def worker(num):
return num * num

# 创建进程池
with multiprocessing.Pool(processes=4) as pool:
results = pool.map(worker, [1, 2, 3, 4, 5])
print(results) # [1, 4, 9, 16, 25]

# 进程间通信(Queue)
def producer(queue):
for item in ["A", "B", "C"]:
queue.put(item)

def consumer(queue):
while True:
item = queue.get()
if item is None:
break
print(f"Consumed: {item}")

if __name__ == "__main__":
queue = multiprocessing.Queue()
p1 = multiprocessing.Process(target=producer, args=(queue,))
p2 = multiprocessing.Process(target=consumer, args=(queue,))
p1.start()
p2.start()
p1.join()
queue.put(None)
p2.join()

6.3 concurrent.futures(高级并发接口)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

# 线程池
with ThreadPoolExecutor(max_workers=4) as executor:
future = executor.submit(worker, "task1")
result = future.result()

results = list(executor.map(worker, ["task1", "task2", "task3"]))

# 进程池(CPU 密集型任务)
with ProcessPoolExecutor(max_workers=4) as executor:
results = executor.map(intensive_computation, data)

# 获取 Future 对象
futures = [executor.submit(task, arg) for arg in args]
for future in concurrent.futures.as_completed(futures):
result = future.result()

7. 数据持久化

7.1 json(JSON 序列化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import json

# 序列化
data = {"name": "Alice", "age": 30, "hobbies": ["reading", "coding"]}
json_str = json.dumps(data, indent=2, ensure_ascii=False)

# 写入文件
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)

# 反序列化
json_str = '{"name": "Alice", "age": 30}'
data = json.loads(json_str)

# 从文件读取
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)

# 自定义编码器
class PersonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Person):
return {"name": obj.name, "age": obj.age}
return super().default(obj)

json.dumps(person, cls=PersonEncoder)

7.2 pickle(对象序列化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pickle

# 序列化
data = {"name": "Alice", "age": 30}
pickled = pickle.dumps(data)

# 写入文件
with open("data.pkl", "wb") as f:
pickle.dump(data, f)

# 反序列化
data = pickle.loads(pickled)

# 从文件读取
with open("data.pkl", "rb") as f:
data = pickle.load(f)

JSON vs Pickle

特性 JSON Pickle
可读性 人类可读 二进制格式
兼容性 跨语言 仅 Python
支持类型 基础类型 几乎所有 Python 对象
安全性 安全 有安全风险(不要加载不可信数据)
文件大小 较大 较小

7.3 sqlite3(轻量级数据库)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import sqlite3

# 连接数据库(不存在则创建)
conn = sqlite3.connect("example.db")
cursor = conn.cursor()

# 创建表
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER
)
""")

# 插入数据
cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", ("Alice", 30))
conn.commit()

# 查询数据
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
for row in rows:
print(row)

# 参数化查询(防止 SQL 注入)
cursor.execute("SELECT * FROM users WHERE age > ?", (25,))

# 使用上下文管理器
with sqlite3.connect("example.db") as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")

conn.close()

8. 时间与日期

8.1 time 模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time

# 时间戳(秒)
now = time.time()
print(now) # 1721430000.0

# 格式化时间
print(time.strftime("%Y-%m-%d %H:%M:%S")) # 2024-07-20 10:30:00
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

# 解析时间
parsed = time.strptime("2024-07-20", "%Y-%m-%d")
print(parsed) # time.struct_time(tm_year=2024, ...)

# 睡眠
print("开始")
time.sleep(1)
print("1秒后")

# 性能计时
start = time.perf_counter()
# do_something()
elapsed = time.perf_counter() - start

8.2 datetime 模块(最常用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from datetime import datetime, date, time, timedelta, timezone
from zoneinfo import ZoneInfo # 3.9+

# 当前时间
now = datetime.now()
utc_now = datetime.now(timezone.utc)

# 创建特定时间
dt = datetime(2024, 7, 20, 10, 30, 0)

# 格式化
print(dt.strftime("%Y-%m-%d %H:%M:%S"))
print(dt.isoformat()) # 2024-07-20T10:30:00

# 解析
parsed = datetime.fromisoformat("2024-07-20T10:30:00")

# 时间运算
future = dt + timedelta(days=7, hours=3)
diff = future - dt
print(diff.days) # 7

# 时区处理(3.9+ 推荐)
nyc = ZoneInfo("America/New_York")
shanghai = ZoneInfo("Asia/Shanghai")

dt_shanghai = datetime(2024, 7, 20, 10, 30, tzinfo=shanghai)
dt_nyc = dt_shanghai.astimezone(nyc)
print(f"上海: {dt_shanghai}")
print(f"纽约: {dt_nyc}")

# 时间戳转换
timestamp = dt.timestamp()
print(datetime.fromtimestamp(timestamp))

strftime 格式代码

代码 含义 示例
%Y 4 位年份 2024
%m 2 位月份 07
%d 2 位日期 20
%H 24 小时制 15
%M 分钟 30
%S 00
%A 星期全称 Saturday
%a 星期缩写 Sat

8.3 calendar

1
2
3
4
5
6
7
8
9
10
11
import calendar

# 打印月历
print(calendar.month(2024, 7))

# 判断闰年
print(calendar.isleap(2024)) # True

# 某月第一天是星期几,该月有多少天
first_weekday, days_in_month = calendar.monthrange(2024, 7)
print(f"7月有{days_in_month}天,第一天是星期{first_weekday}")

9. 数学与随机

9.1 mathcmath

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import math

print(math.sqrt(16)) # 4.0
print(math.pow(2, 10)) # 1024.0
print(math.log(100, 10)) # 2.0
print(math.log2(1024)) # 10.0
print(math.exp(1)) # 2.718...
print(math.factorial(5)) # 120
print(math.gcd(48, 18)) # 6
print(math.pi, math.e) # 3.14159... 2.71828...
print(math.floor(3.7)) # 3
print(math.ceil(3.2)) # 4
print(math.trunc(3.9)) # 3

# 三角函数
print(math.sin(math.pi / 2)) # 1.0
print(math.degrees(math.pi)) # 180.0

# 双曲函数
print(math.sinh(1)) # 1.1752...

# 特殊函数
print(math.erf(1)) # 误差函数
print(math.gamma(5)) # 伽马函数

9.2 randomsecrets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import random
import secrets

# random:伪随机(可预测,不用于安全场景)
print(random.random()) # [0, 1) 浮点数
print(random.randint(1, 100)) # [1, 100] 整数
print(random.choice(["A", "B", "C"]))
print(random.choices(["A", "B", "C"], k=10, weights=[5, 3, 2]))
print(random.shuffle([1, 2, 3, 4, 5])) # 原地打乱
print(random.sample([1, 2, 3, 4, 5], 3)) # 不重复抽样

# secrets:密码学安全的随机(用于 token、密码等)
token = secrets.token_hex(16) # 32 字符随机十六进制
url_safe = secrets.token_urlsafe(16) # URL 安全的随机字符串
secure_choice = secrets.choice(["A", "B", "C"])

random vs secrets 对比

特性 random secrets
随机性 伪随机(可复现) 密码学安全(不可预测)
用途 游戏、模拟、测试 Token、密码、验证码
可重复性 可通过 seed 复现 不可复现

9.3 statisticsdecimal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import statistics
from decimal import Decimal, getcontext

# statistics:基础统计
data = [1, 2, 2, 3, 4, 5, 5, 5]
print(statistics.mean(data)) # 平均数
print(statistics.median(data)) # 中位数
print(statistics.mode(data)) # 众数
print(statistics.stdev(data)) # 标准差
print(statistics.quantiles(data)) # 分位数

# decimal:精确小数(金融计算)
getcontext().prec = 6 # 设置全局精度
a = Decimal("0.1")
b = Decimal("0.2")
print(a + b) # 0.3(精确!)

# 不要用 float 构造 Decimal
print(Decimal(0.1)) # 不精确
print(Decimal("0.1")) # 精确

# 高精度计算
getcontext().prec = 20
result = Decimal("1") / Decimal("7")
print(result) # 0.14285714285714285714

浮点精度问题

1
2
3
4
5
6
# 浮点精度陷阱
print(0.1 + 0.2) # 0.30000000000000004(不精确!)

# 使用 decimal 解决
from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2")) # 0.3(精确!)

10. 并发与并行

10.1 threading 与 GIL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import threading
import time

def worker(name, delay):
print(f"线程 {name} 开始")
time.sleep(delay)
print(f"线程 {name} 结束")

# 创建并启动线程
threads = []
for i in range(3):
t = threading.Thread(target=worker, args=(f"T{i}", 1))
t.start()
threads.append(t)

# 等待所有线程完成
for t in threads:
t.join()

# 线程安全:Lock
from threading import Lock
counter = 0
lock = Lock()

def increment():
global counter
for _ in range(100000):
with lock: # 获取锁
counter += 1

# 线程本地存储
local = threading.local()
local.user_id = "123" # 每个线程独立

GIL(全局解释器锁)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──────────────────────────────────────────────┐
│ Python 解释器 │
├──────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────┐ │
│ │ GIL(全局解释器锁) │ │
│ └───────────────┬──────────────────────┘ │
│ │ │
│ ┌───────────────┴───────────────┐ │
│ │ │ │
│ │ Thread 1 │ Thread 2 │ │
│ │ Python代码 │ Python代码 │ │
│ │ │ │ │
│ └─────────────┴─────────────────┘ │
│ │
│ 同一时刻只有一个线程执行 Python 字节码 │
│ I/O 操作时会释放 GIL │
└──────────────────────────────────────────────┘

10.2 concurrent.futures

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed
import requests

# 线程池(I/O 密集型)
with ThreadPoolExecutor(max_workers=5) as executor:
urls = ["http://example.com"] * 10
# map:按顺序返回结果
results = executor.map(fetch_url, urls)

# submit:异步提交,可获取 Future
futures = [executor.submit(fetch_url, url) for url in urls]
for future in as_completed(futures):
try:
result = future.result()
print(result)
except Exception as e:
print(f"错误: {e}")

# 进程池(CPU 密集型,绕过 GIL)
with ProcessPoolExecutor(max_workers=4) as executor:
numbers = range(100)
results = list(executor.map(is_prime, numbers))

def fetch_url(url):
return requests.get(url, timeout=5).status_code

10.3 multiprocessing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from multiprocessing import Pool, Queue, Process

def square(n):
return n * n

# 进程池
if __name__ == "__main__":
with Pool(4) as p:
results = p.map(square, range(10))
print(results) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 进程间通信
from multiprocessing import Manager

with Manager() as manager:
shared_dict = manager.dict()
shared_list = manager.list()

10.4 asyncio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import asyncio

async def fetch(url):
await asyncio.sleep(0.1) # 模拟异步 I/O
return f"Data from {url}"

async def main():
urls = ["url1", "url2", "url3"]

# gather:并发执行
results = await asyncio.gather(
*(fetch(url) for url in urls)
)

# 创建任务
tasks = [asyncio.create_task(fetch(url)) for url in urls]
for task in asyncio.as_completed(tasks):
result = await task
print(result)

# asyncio.run(main())

并发模型选择

场景 推荐方案 原因
I/O 密集型(网络请求) asyncio 单线程高并发,内存开销低
I/O 密集型(简单) ThreadPoolExecutor 代码简单,可调用同步库
CPU 密集型 ProcessPoolExecutor 绕过 GIL,利用多核
大量 CPU 计算 multiprocessing 更灵活的进程控制

11. 网络与通信

11.1 socket 基础

1
2
3
4
5
6
7
8
9
10
11
12
13
import socket

# TCP 客户端
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(("example.com", 80))
s.sendall(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
data = s.recv(4096)
print(data.decode())

# UDP
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.sendto(b"Hello", ("localhost", 9999))
data, addr = s.recvfrom(1024)

11.2 http.clienturllib

1
2
3
4
5
6
7
8
9
10
11
# 标准库的 HTTP 请求(生产环境推荐使用 requests 第三方库)
import urllib.request
import json

req = urllib.request.Request(
"https://api.example.com/data",
headers={"Accept": "application/json"}
)
with urllib.request.urlopen(req, timeout=10) as response:
data = json.loads(response.read())
print(data)

11.3 email 模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

msg = MIMEMultipart()
msg["From"] = "sender@example.com"
msg["To"] = "recipient@example.com"
msg["Subject"] = "测试邮件"

body = MIMEText("这是邮件正文", "plain", "utf-8")
msg.attach(body)

# 发送(需要 SMTP 服务器)
# import smtplib
# with smtplib.SMTP("smtp.example.com") as server:
# server.send_message(msg)

12. 开发支持

12.1 unittest 测试框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import unittest
from unittest.mock import Mock, patch, MagicMock

class TestStringMethods(unittest.TestCase):
def setUp(self):
"""每个测试方法前执行。"""
self.sample = "hello world"

def tearDown(self):
"""每个测试方法后执行。"""
pass

def test_upper(self):
self.assertEqual("foo".upper(), "FOO")

def test_isupper(self):
self.assertTrue("FOO".isupper())
self.assertFalse("Foo".isupper())

def test_split(self):
s = "hello world"
self.assertEqual(s.split(), ["hello", "world"])
with self.assertRaises(TypeError):
s.split(2)

@patch("module.ClassName.method")
def test_with_mock(self, mock_method):
mock_method.return_value = "mocked"
result = module.ClassName().method()
self.assertEqual(result, "mocked")

# 运行测试
# python -m unittest test_module

12.2 doctest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def factorial(n):
"""计算阶乘。

>>> factorial(5)
120
>>> factorial(0)
1
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
"""
if n < 0:
raise ValueError("n must be >= 0")
if n <= 1:
return 1
return n * factorial(n - 1)

# 运行 doctest
# python -m doctest your_module.py -v

12.3 timeit 与性能分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import timeit

# 简单计时
elapsed = timeit.timeit("sum(range(1000))", number=10000)
print(f"耗时: {elapsed:.4f}s")

# 命令行使用
# python -m timeit "sum(range(1000))"

# cProfile:函数级性能分析
import cProfile
import pstats

def slow_function():
return sum(i ** 2 for i in range(100000))

profiler = cProfile.Profile()
profiler.enable()
slow_function()
profiler.disable()

stats = pstats.Stats(profiler)
stats.sort_stats("cumulative")
stats.print_stats(10) # 打印前 10 个耗时函数

12.4 enum 枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from enum import Enum, auto, IntEnum

class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3

print(Color.RED) # Color.RED
print(Color.RED.name) # RED
print(Color.RED.value) # 1
print(Color(1)) # Color.RED

# 自动赋值
class Status(Enum):
PENDING = auto()
RUNNING = auto()
COMPLETED = auto()

# IntEnum:可作为整数使用
class Priority(IntEnum):
LOW = 1
MEDIUM = 2
HIGH = 3

print(Priority.HIGH > Priority.LOW) # True

# 枚举比较
print(Color.RED == Color.GREEN) # False
print(Color.RED != Color.GREEN) # True

13. 其他实用模块

13.1 base64 编码

1
2
3
4
5
6
7
8
9
10
11
import base64

encoded = base64.b64encode(b"hello").decode() # aGVsbG8=
decoded = base64.b64decode(encoded) # b'hello'

# URL 安全编码
url_safe = base64.urlsafe_b64encode(b"hello?world").decode()

# 文件编码(处理二进制数据)
with open("image.png", "rb") as f:
encoded_img = base64.b64encode(f.read()).decode()

13.2 inspect 内省

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import inspect

def example(a: int, b: str = "default") -> bool:
"""示例函数。"""
return True

# 获取函数签名
sig = inspect.signature(example)
for name, param in sig.parameters.items():
print(f"{name}: {param.annotation}, default={param.default}")

# 获取源码
print(inspect.getsource(example))

# 获取调用栈
print(inspect.stack())

# 判断对象类型
print(inspect.isfunction(example)) # True
print(inspect.ismethod(example)) # False

# 获取类的所有方法
class MyClass:
def method1(self):
pass
def method2(self):
pass

methods = inspect.getmembers(MyClass, predicate=inspect.isfunction)
print([name for name, _ in methods]) # ['method1', 'method2']

13.3 weakref:弱引用

弱引用不增加对象的引用计数,用于解决循环引用问题,以及实现缓存、观察者等场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import weakref

class Node:
def __init__(self, value):
self.value = value
self._parent = None # 强引用
self._children = [] # 强引用

@property
def parent(self):
"""使用弱引用避免循环引用。"""
return self._parent() if self._parent else None

@parent.setter
def parent(self, node):
self._parent = weakref.ref(node) if node else None

def add_child(self, child):
self._children.append(child)
child.parent = self

# 弱引用被回收时的回调
def on_delete(obj):
print(f"对象被回收: {obj}")

data = {"key": "value"}
ref = weakref.ref(data, on_delete) # 注册回调
print(ref()) # {'key': 'value'} —— 获取原对象

del data # 删除原对象
print(ref()) # None —— 原对象已被回收

# WeakValueDictionary:值被回收时自动删除条目
cache = weakref.WeakValueDictionary()
obj = Node("temp")
cache["temp"] = obj
print(len(cache)) # 1
del obj
print(len(cache)) # 0(自动移除)

# 工程场景:缓存系统、观察者模式(避免阻止观察者回收)、对象池

13.4 copy 模块深度解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import copy

# 浅拷贝 vs 深拷贝的底层原理
class Container:
def __init__(self, items):
self.items = items

original = Container([[1, 2], [3, 4]])

# 浅拷贝:只复制最外层,内层对象共享引用
shallow = copy.copy(original)
print(shallow.items is original.items) # True(内层同一对象)
shallow.items[0].append(99)
print(original.items) # [[1, 2, 99], [3, 4]] —— 被影响了!

# 深拷贝:递归复制所有嵌套对象
deep = copy.deepcopy(original)
print(deep.items is original.items) # False(内层独立对象)
deep.items[0].append(88)
print(original.items) # [[1, 2, 99], [3, 4]] —— 不受影响

# 自定义拷贝行为
class Custom:
def __init__(self, value):
self.value = value

def __copy__(self):
"""浅拷贝自定义。"""
return Custom(self.value)

def __deepcopy__(self, memo):
"""深拷贝自定义。注意 memo 参数用于处理循环引用。"""
return Custom(copy.deepcopy(self.value, memo))

# 拷贝策略选择
# | 场景 | 选择 | 原因 |
# |------|------|------|
# | 不可变对象(int、str、tuple)| 无需拷贝 | 赋值即引用 |
# | 简单容器(列表/字典值类型)| 浅拷贝 | 性能好,够用 |
# | 嵌套容器(列表嵌套列表)| 深拷贝 | 需要完全独立副本 |
# | 大对象 | 自定义 __copy__ | 只拷贝需要的部分 |

14. 工作实战场景

14.1 数据处理管道

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import itertools
from collections import Counter

class DataPipeline:
"""数据处理管道:流式处理大数据。"""

def __init__(self, data_iter):
self.data_iter = data_iter

def filter(self, predicate):
"""过滤数据。"""
return DataPipeline(filter(predicate, self.data_iter))

def map(self, func):
"""转换数据。"""
return DataPipeline(map(func, self.data_iter))

def group_by(self, key_func):
"""按键分组。"""
sorted_data = sorted(self.data_iter, key=key_func)
groups = []
for key, group in itertools.groupby(sorted_data, key=key_func):
groups.append((key, list(group)))
return groups

def count_by(self, key_func):
"""按键计数。"""
counter = Counter(key_func(item) for item in self.data_iter)
return counter

def collect(self):
"""收集结果。"""
return list(self.data_iter)

# 使用示例
data = [
{"name": "Alice", "category": "A", "value": 10},
{"name": "Bob", "category": "B", "value": 20},
{"name": "Charlie", "category": "A", "value": 30},
]

pipeline = DataPipeline(data)
result = pipeline \
.filter(lambda x: x["value"] > 15) \
.group_by(lambda x: x["category"])

print(result)

14.2 高性能缓存系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from functools import lru_cache
import time
from threading import Lock

class CacheManager:
"""缓存管理器:支持多种缓存策略。"""

def __init__(self):
self._caches = {}
self._lock = Lock()

def get_cache(self, name, maxsize=128):
"""获取或创建缓存。"""
with self._lock:
if name not in self._caches:
def decorator(func):
@lru_cache(maxsize=maxsize)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
self._caches[name] = decorator
return self._caches[name]

def clear_cache(self, name):
"""清空指定缓存。"""
with self._lock:
if name in self._caches:
# lru_cache 装饰的函数有 cache_clear 方法
pass

# 使用示例
cache_manager = CacheManager()

@cache_manager.get_cache("user_cache", maxsize=100)
def get_user(user_id):
"""模拟数据库查询。"""
time.sleep(0.1) # 模拟耗时操作
return {"id": user_id, "name": f"User {user_id}"}

# 首次调用:慢
start = time.time()
user = get_user(1)
print(f"首次调用耗时: {time.time() - start:.3f}s")

# 缓存命中:快
start = time.time()
user = get_user(1)
print(f"缓存命中耗时: {time.time() - start:.3f}s")

14.3 日志分析工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import re
from collections import Counter
from pathlib import Path

class LogAnalyzer:
"""日志分析工具:统计访问频率、错误类型等。"""

def __init__(self, log_path):
self.log_path = Path(log_path)
self._pattern = re.compile(
r'(?P<ip>\d+\.\d+\.\d+\.\d+) - - \[(?P<time>.*?)\] '
r'"(?P<method>\w+) (?P<path>.*?) HTTP/1\.\d" '
r'(?P<status>\d+) (?P<size>\d+)'
)

def parse_logs(self):
"""解析日志文件,返回生成器。"""
with open(self.log_path, "r", encoding="utf-8") as f:
for line in f:
match = self._pattern.match(line)
if match:
yield match.groupdict()

def get_ip_stats(self):
"""统计 IP 访问次数。"""
counter = Counter(entry["ip"] for entry in self.parse_logs())
return counter.most_common(10)

def get_status_stats(self):
"""统计状态码分布。"""
counter = Counter(entry["status"] for entry in self.parse_logs())
return dict(counter)

def get_top_paths(self):
"""统计访问最多的路径。"""
counter = Counter(entry["path"] for entry in self.parse_logs())
return counter.most_common(10)

# 使用示例
analyzer = LogAnalyzer("access.log")
print("Top IP:", analyzer.get_ip_stats())
print("Status分布:", analyzer.get_status_stats())
print("Top Paths:", analyzer.get_top_paths())

14.4 并发任务调度器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from concurrent.futures import ThreadPoolExecutor, as_completed
import time

class TaskScheduler:
"""任务调度器:并发执行任务并收集结果。"""

def __init__(self, max_workers=5):
self.executor = ThreadPoolExecutor(max_workers=max_workers)

def submit(self, task_func, *args, **kwargs):
"""提交单个任务。"""
return self.executor.submit(task_func, *args, **kwargs)

def run_all(self, tasks):
"""并行执行所有任务。"""
futures = [self.executor.submit(task) for task in tasks]

results = []
errors = []

for future in as_completed(futures):
try:
results.append(future.result())
except Exception as e:
errors.append(e)

return results, errors

def shutdown(self):
"""关闭调度器。"""
self.executor.shutdown(wait=True)

# 使用示例
def fetch_data(url):
"""模拟网络请求。"""
time.sleep(0.5)
return f"Data from {url}"

scheduler = TaskScheduler(max_workers=3)
tasks = [
lambda: fetch_data("http://api1.example.com"),
lambda: fetch_data("http://api2.example.com"),
lambda: fetch_data("http://api3.example.com"),
]

results, errors = scheduler.run_all(tasks)
print("Results:", results)
scheduler.shutdown()

15. 常见面试题汇总

15.1 基础概念题

Q1:collections 模块中 defaultdict 和普通 dict 的区别?

Adefaultdict 在访问不存在的键时会自动创建该键,并使用 default_factory 提供默认值。普通 dict 会抛出 KeyError


Q2:itertools.chainlist.extend 的区别?

Aitertools.chain 返回一个迭代器,不立即合并列表,内存效率更高;list.extend 会立即将所有元素添加到列表中,占用更多内存。


Q3:heapq 实现的是最大堆还是最小堆?如何实现最大堆?

Aheapq 实现的是最小堆。要实现最大堆,可以将元素取负值后存储。


Q4:functools.lru_cache 的工作原理是什么?

Alru_cache 使用最近最少使用算法缓存函数结果。当缓存满时,会淘汰最近最少使用的条目。它通过装饰器实现,自动将函数参数作为键缓存结果。


Q5:concurrent.futures.ThreadPoolExecutorProcessPoolExecutor 的区别?

A

  • ThreadPoolExecutor:线程池,适用于 I/O 密集型任务,受 GIL 限制,同一时刻只有一个线程执行 Python 字节码
  • ProcessPoolExecutor:进程池,适用于 CPU 密集型任务,绕过 GIL,利用多核处理器

15.2 实战应用题

Q6:如何选择合适的并发模型?

A

  • I/O 密集型(网络请求、文件读写):asyncio(单线程高并发)或 ThreadPoolExecutor(简单)
  • CPU 密集型(计算任务):ProcessPoolExecutor(绕过 GIL)
  • 需要大量进程控制:multiprocessing

Q7:如何处理浮点数精度问题?

A

  1. 使用 decimal 模块进行精确小数计算
  2. 避免直接比较浮点数,使用容差比较(abs(a - b) < 1e-9
  3. 对于金融计算,使用 decimal 或整数(以分为单位)

Q8:如何实现高效的缓存系统?

A

  1. 使用 functools.lru_cache 装饰器(简单场景)
  2. 实现自定义缓存类(复杂场景)
  3. 使用 weakref.WeakValueDictionary(自动回收缓存)
  4. 设置合理的缓存过期策略

Q9:如何进行性能分析?

A

  1. timeit:简单计时,比较代码片段
  2. cProfile:函数级性能分析,找出耗时函数
  3. line_profiler(第三方):行级性能分析
  4. memory_profiler(第三方):内存使用分析

Q10:re.compile() 的作用是什么?何时使用?

Are.compile() 用于编译正则表达式,生成正则表达式对象。对于频繁使用的正则表达式,编译后复用可以提升性能(避免重复编译)。


15.3 代码分析题

Q11:分析以下代码的问题:

1
2
3
4
5
6
7
import re

text = "email: test@example.com"
if re.match(r"\w+@\w+\.\w+", text):
print("匹配成功")
else:
print("匹配失败")

Are.match() 只从字符串开头匹配,而 email: test@example.com 开头是 “email:”,所以匹配失败。应使用 re.search()


Q12:分析以下代码的问题:

1
2
3
4
5
6
7
8
from collections import defaultdict

data = [("A", 1), ("B", 2), ("A", 3)]
groups = defaultdict(list)
for key, value in data:
groups[key].append(value)

print(dict(groups))

A:这段代码没有问题,是正确的分组方式。输出为 {'A': [1, 3], 'B': [2]}


Q13:以下代码的输出是什么?

1
2
3
4
5
6
import heapq

nums = [3, 1, 4, 1, 5, 9]
heapq.heapify(nums)
print(heapq.heappop(nums))
print(heapq.heappop(nums))

A:输出为 11heapify 将列表转为最小堆,heappop 每次弹出最小元素。


16. 实战项目:日志分析系统

16.1 项目概述

项目目标:开发一个命令行日志分析工具 loganalyzer,支持分析 Web 服务器日志。

功能需求

  • loganalyzer access <logfile> - 分析访问日志
  • loganalyzer errors <logfile> - 统计错误类型
  • loganalyzer top <logfile> - 显示 Top 访问 IP/路径
  • loganalyzer export <logfile> <output> - 导出分析结果

16.2 项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
loganalyzer/
├── README.md
├── pyproject.toml
├── src/
│ └── loganalyzer/
│ ├── __init__.py
│ ├── __main__.py
│ ├── cli.py
│ ├── analyzer.py
│ ├── parsers/
│ │ ├── __init__.py
│ │ └── nginx_parser.py
│ └── exporters/
│ ├── __init__.py
│ └── json_exporter.py
└── tests/
├── __init__.py
└── test_analyzer.py

16.3 核心代码

pyproject.toml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "loganalyzer"
version = "1.0.0"
description = "A log analysis tool"
readme = "README.md"
license = {text = "MIT"}
authors = [
{name = "Your Name", email = "you@example.com"}
]
requires-python = ">=3.9"
dependencies = [
"click>=8.0",
]

[project.scripts]
loganalyzer = "loganalyzer.cli:main"

[tool.setuptools.packages.find]
where = ["src"]

cli.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import click
from loganalyzer.analyzer import LogAnalyzer

@click.group()
def main():
"""LogAnalyzer - 日志分析工具"""
pass

@main.command("access")
@click.argument("logfile")
def analyze_access(logfile):
"""分析访问日志。"""
analyzer = LogAnalyzer(logfile)
stats = analyzer.get_access_stats()
click.echo(f"总访问次数: {stats['total']}")
click.echo(f"平均响应大小: {stats['avg_size']:.2f} bytes")

@main.command("errors")
@click.argument("logfile")
def analyze_errors(logfile):
"""统计错误类型。"""
analyzer = LogAnalyzer(logfile)
errors = analyzer.get_error_stats()
for status, count in errors.items():
click.echo(f"{status}: {count} 次")

@main.command("top")
@click.argument("logfile")
@click.option("-t", "--type", default="ip", type=click.Choice(["ip", "path"]))
def show_top(logfile, type):
"""显示 Top IP 或路径。"""
analyzer = LogAnalyzer(logfile)
if type == "ip":
top = analyzer.get_top_ips()
else:
top = analyzer.get_top_paths()

click.echo(f"Top 10 {type}:")
for item, count in top:
click.echo(f" {item}: {count}")

@main.command("export")
@click.argument("logfile")
@click.argument("output")
def export_results(logfile, output):
"""导出分析结果。"""
analyzer = LogAnalyzer(logfile)
analyzer.export(output)
click.echo(f"结果已导出到: {output}")

analyzer.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from collections import Counter
from loganalyzer.parsers.nginx_parser import NginxParser
from loganalyzer.exporters.json_exporter import JsonExporter

class LogAnalyzer:
"""日志分析器。"""

def __init__(self, logfile):
self.logfile = logfile
self.parser = NginxParser()
self.exporter = JsonExporter()

def get_entries(self):
"""获取所有日志条目。"""
return self.parser.parse(self.logfile)

def get_access_stats(self):
"""获取访问统计。"""
entries = self.get_entries()
total = len(entries)
total_size = sum(int(e["size"]) for e in entries)

return {
"total": total,
"avg_size": total_size / total if total > 0 else 0,
}

def get_error_stats(self):
"""获取错误统计。"""
entries = self.get_entries()
errors = [e["status"] for e in entries if e["status"].startswith("4") or e["status"].startswith("5")]
return dict(Counter(errors))

def get_top_ips(self):
"""获取 Top IP。"""
entries = self.get_entries()
counter = Counter(e["ip"] for e in entries)
return counter.most_common(10)

def get_top_paths(self):
"""获取 Top 路径。"""
entries = self.get_entries()
counter = Counter(e["path"] for e in entries)
return counter.most_common(10)

def export(self, output):
"""导出分析结果。"""
data = {
"access_stats": self.get_access_stats(),
"error_stats": self.get_error_stats(),
"top_ips": self.get_top_ips(),
"top_paths": self.get_top_paths(),
}
self.exporter.export(data, output)

parsers/nginx_parser.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import re

class NginxParser:
"""Nginx 日志解析器。"""

def __init__(self):
self._pattern = re.compile(
r'(?P<ip>\d+\.\d+\.\d+\.\d+) - - \[(?P<time>.*?)\] '
r'"(?P<method>\w+) (?P<path>.*?) HTTP/1\.\d" '
r'(?P<status>\d+) (?P<size>\d+)'
)

def parse(self, logfile):
"""解析日志文件。"""
entries = []
with open(logfile, "r", encoding="utf-8") as f:
for line in f:
match = self._pattern.match(line)
if match:
entries.append(match.groupdict())
return entries

exporters/json_exporter.py

1
2
3
4
5
6
7
8
9
import json

class JsonExporter:
"""JSON 导出器。"""

def export(self, data, output):
"""导出数据到 JSON 文件。"""
with open(output, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)

16.4 项目运行

1
2
3
4
5
6
7
8
9
10
11
12
# 开发模式安装
pip install -e .

# 使用命令
loganalyzer access access.log # 分析访问统计
loganalyzer errors access.log # 统计错误
loganalyzer top access.log --type ip # Top IP
loganalyzer top access.log --type path # Top 路径
loganalyzer export access.log result.json

# 或者使用 python -m
python -m loganalyzer access access.log

16.5 项目亮点

  1. 模块化设计:解析器和导出器独立,易于扩展
  2. 正则优化:预编译正则表达式,提升性能
  3. 流式处理:逐行读取日志,内存效率高
  4. 命令行友好:使用 click 库,提供丰富的命令和选项

附录:第八阶段自检清单

在继续学习第九阶段之前,请确保你能:

  • 使用 re 模块完成常见的匹配、查找、替换操作
  • 使用 collections 中的 dequeCounterdefaultdictnamedtuple
  • 使用 heapq 实现优先队列,使用 bisect 维护有序列表
  • 使用 itertools 生成排列组合、无限序列、分组
  • 使用 datetime 进行时间计算、格式化、时区转换
  • 使用 decimal 进行精确的小数计算
  • 使用 secrets 生成安全的随机数和 token
  • 选择合适的并发模型(threading/multiprocessing/asyncio)
  • 使用 concurrent.futures 的线程池/进程池
  • 编写 unittest 测试用例,使用 mock 进行依赖隔离
  • 使用 argparse 处理命令行参数
  • 使用 base64 进行编码解码
  • 使用 inspect 进行代码内省
  • 使用 weakref 解决循环引用问题
  • 区分浅拷贝和深拷贝的使用场景

工程师寄语:标准库是 Python 最大的宝藏。在考虑安装第三方包之前,先问一句:”标准库里有吗?” 熟悉标准库不仅能减少依赖,还能提高代码的可维护性和可移植性。collectionsitertoolsfunctools 这三个模块特别值得反复研读。

性能提示:对于频繁调用的正则表达式,务必使用 re.compile() 编译后复用。对于大数据量处理,优先使用 itertools 和生成器表达式,避免一次性加载所有数据到内存。