Python 基础体系 · 第 1/112 篇。示例统一以 Python 3.14 为语言基线;第三方库使用与其兼容的现代稳定版本,版本敏感行为会单独说明。

Python 完整学习路线:从语言模型、并发到 Web、数据、AI 与生产交付

先建立正确的路线观

Python 学习通常有两种失败方式。

第一种是只学语法:会写变量、循环、函数,却解释不了“为什么这个列表被另一个函数改了”“为什么 await 不能直接放在普通函数里”“为什么 Web 服务加了线程却没有变快”。

第二种是只学框架:直接进入 Web、数据分析或 AI 库,能够拼出功能,却不了解对象生命周期、异常传播、并发边界、数据库事务和进程模型。一旦需求变复杂,问题就从“不会调用 API”升级为“无法解释系统行为”。

完整路线应当按以下依赖关系推进:

flowchart LR
    A[运行环境与工具] --> B[语言模型]
    B --> C[数据模型与函数]
    C --> D[模块 类型 测试]
    D --> E[并发模型]
    E --> F[Web 与网络]
    E --> G[数据与数据库]
    F --> H[服务化]
    G --> H
    H --> I[AI 应用]
    H --> J[生产交付]
    I --> J

这里的“语言模型”指 Python 语言的执行模型,不是大语言模型。它回答的是:

  • 名称如何绑定到对象;
  • 对象具有什么身份、类型和值;
  • 表达式如何求值;
  • 函数调用如何建立作用域;
  • 异常如何传播;
  • 协程如何挂起和恢复;
  • 模块如何导入和初始化。

Python 3.14 的官方语言参考将这些内容组织在数据模型、执行模型、表达式、语句、导入系统和协程等章节中;语言参考强调的是语法与核心语义,具体内置类型和标准库 API 则由标准库文档描述。(docs.python.org)

因此,路线不是“先学若干库,再把它们串起来”,而是从语言语义开始,逐步建立能够支撑并发、服务、数据和交付的心智模型。


一、起点:解释器、环境和可重复运行

1. Python 程序到底如何运行

一个 Python 程序至少涉及四层:

  1. 源代码.py 文件中的字符。
  2. 编译结果:解释器将源代码编译为代码对象,通常包含字节码。
  3. 运行时对象:整数、字符串、函数、类、模块等对象。
  4. 执行上下文:当前栈帧、局部命名空间、全局命名空间、异常状态和导入状态。

“解释执行”并不意味着 Python 每次逐字符解释源代码。实现通常会先把源代码解析并编译,再由虚拟机执行代码对象;但语言规范主要保证程序的语义,不保证某个具体解释器一定使用某种字节码或内存布局。

需要区分:

  • 规范保证:例如名称绑定、异常传播、比较运算的语义。
  • CPython 实现细节:例如 id() 在 CPython 中通常对应对象的内存地址。
  • 经验性行为:例如小整数或某些字符串可能被缓存,不能用于推断对象身份。

2. 创建项目环境

Python 的虚拟环境用于隔离项目解释器、库和脚本。官方 venv 文档明确说明,虚拟环境默认与基础 Python 安装中的第三方包隔离,环境本身应视为可删除、可重建的目录,而不是存放源代码的地方。(docs.python.org)

mkdir python-route-demo
cd python-route-demo

python3.14 -m venv .venv
source .venv/bin/activate       # Linux/macOS
# Windows PowerShell:
# .venv\Scripts\Activate.ps1

python --version
python -m pip --version

预期结果类似:

Python 3.14.x
pip 25.x from .../.venv/lib/python3.14/site-packages/pip

使用 python -m pip 而不是直接使用 pip,是为了明确调用的是当前 python 对应环境中的安装工具。否则系统上可能同时存在多个 Python 和多个 pip,最终出现“安装成功但程序找不到包”的路径错配。

.venv 不应提交到 Git。交付时应提交依赖声明或锁定文件,并在目标环境重新创建虚拟环境。虚拟环境不是可移动的运行时镜像;它通常包含指向创建时基础 Python 的路径,复制到另一台机器后可能失效。(docs.python.org)


二、核心语言模型:名称不是盒子,赋值不是复制

这是整条路线中最重要的基础。

1. 对象的三个属性

Python 中的数据以对象表示。每个对象都有:

  • 身份 identity:对象是哪一个对象;
  • 类型 type:对象支持哪些操作;
  • 值 value:对象当前代表什么内容。

对象身份一旦创建就不会改变;对象类型也不会改变;对象的值则可能可变或不可变。列表和字典通常是可变对象,整数、字符串和元组通常是不可变对象。(docs.python.org)

可以用一个关系表示名称绑定:

NbindON \xrightarrow{\text{bind}} O

其中:

  • NN 是命名空间中的名称;
  • OO 是对象;
  • 箭头表示名称当前绑定到对象。

名称不是装值的盒子。执行:

x = 10

不是把整数 10 放进名为 x 的容器,而是:

  1. 创建或取得一个值为 10 的整数对象;
  2. 在当前命名空间中建立绑定 x -> 该对象

执行:

x = 20

则是把 x 重新绑定到另一个整数对象,原来的 10 是否销毁,取决于是否还有其他引用。

2. 赋值为什么不是复制

a = [1, 2]
b = a

b.append(3)

print(a)
print(b)
print(a is b)

输出:

[1, 2, 3]
[1, 2, 3]
True

逐步分析:

步骤 a b 对象内容
a = [1, 2] 指向列表对象 L 未绑定 L 为 [1, 2]
b = a 指向 L 指向 L L 仍为 [1, 2]
b.append(3) 指向 L 指向 L L 被原地修改为 [1, 2, 3]

b = a 只增加了一个名称绑定,不会创建新列表。

如果需要浅复制:

a = [1, 2]
b = a.copy()

b.append(3)

print(a)       # [1, 2]
print(b)       # [1, 2, 3]
print(a is b)  # False

但浅复制只复制最外层容器:

a = [[1, 2], [3, 4]]
b = a.copy()

b[0].append(99)

print(a)  # [[1, 2, 99], [3, 4]]
print(b)  # [[1, 2, 99], [3, 4]]

因为:

a -> 外层列表 A -> 内层列表 X
b -> 外层列表 B -> 内层列表 X

copy() 创建了新的外层列表 B,但内层列表 X 仍然共享。需要递归复制时才考虑 copy.deepcopy(),但深拷贝可能带来更高成本、无法复制某些资源对象,且不能替代清晰的数据所有权设计。

3. 可变与不可变的真正边界

x = 10
y = x

x += 1

print(x)       # 11
print(y)       # 10
print(x is y)  # 通常为 False,但不应依赖身份

整数不可变,因此 x += 1 的效果近似于:

x = x + 1

它创建或取得了一个新整数对象,并让 x 重新绑定。

列表则不同:

x = [10]
y = x

x += [20]

print(x)       # [10, 20]
print(y)       # [10, 20]

对列表而言,+= 通常执行原地扩展,等价效果接近:

x.extend([20])

这也是为什么“+= 一定创建新对象”是错误的说法。

4. 不可变容器也可能观察到内部变化

items = ([1, 2], "stable")
items[0].append(3)

print(items)  # ([1, 2, 3], 'stable')

元组本身不可变:它不能把第一个元素替换成另一个对象。但第一个元素指向的列表可变,因此列表内容仍然可以改变。官方数据模型也特别区分了“容器本身不可变”和“容器内对象不可变”。(docs.python.org)

5. 函数参数是“共享对象引用”

def add_item(values: list[int]) -> None:
    values.append(3)

data = [1, 2]
add_item(data)

print(data)  # [1, 2, 3]

函数接收到的是一个新的局部名称 values,它与调用方的 data 指向同一个列表对象:

调用方: data   ─┐
                ├──> 列表 L
函数内: values ─┘

如果函数重新绑定参数,不会影响调用方:

def replace(values: list[int]) -> None:
    values = [99]

data = [1, 2]
replace(data)

print(data)  # [1, 2]

这里发生的是:

  1. values 最初指向列表 L;
  2. values = [99]values 指向新列表 M;
  3. data 仍然指向 L。

因此应区分:

  • 修改对象:可能被其他引用观察到;
  • 重新绑定名称:只影响该名称所在的作用域。

6. 默认参数的反例

默认参数在函数定义时求值,而不是每次调用时求值:

def append_value(value: int, bucket: list[int] = []) -> list[int]:
    bucket.append(value)
    return bucket

print(append_value(1))  # [1]
print(append_value(2))  # [1, 2]

两次调用共享同一个默认列表对象。

正确写法:

def append_value(value: int, bucket: list[int] | None = None) -> list[int]:
    if bucket is None:
        bucket = []
    bucket.append(value)
    return bucket

None 在这里不是业务数据,而是“调用者没有提供容器”的哨兵。若业务上允许明确传入 None,则应使用专门的哨兵对象:

_MISSING = object()

def read(value=_MISSING):
    if value is _MISSING:
        return "not provided"
    return value

7. 名称解析与闭包

Python 的局部、闭包、全局和内置名称解析通常可概括为 LEGB:

  1. Local:当前函数局部作用域;
  2. Enclosing:外层函数作用域;
  3. Global:模块全局作用域;
  4. Builtins:内置名称作用域。
count = 10

def outer():
    count = 20

    def inner():
        return count

    return inner

f = outer()
print(f())  # 20

inner() 没有局部 count,因此从外层函数闭包中读取 count = 20

如果要修改外层绑定,必须使用 nonlocal

def counter():
    value = 0

    def increment():
        nonlocal value
        value += 1
        return value

    return increment

next_value = counter()
print(next_value())  # 1
print(next_value())  # 2

闭包保存的是外层变量的绑定单元,而不是调用时重新查找一个普通局部变量。理解这一点,才能正确使用装饰器、工厂函数、回调和异步任务。


三、从语法到可维护程序:必须掌握的语言主干

1. 表达式、语句和求值顺序

表达式会产生对象或值:

total = price * quantity

语句改变程序状态:

if total > 100:
    discount = 0.9

学习时不能只记运算符优先级,还要理解求值顺序。函数参数、容器字面量和表达式通常按照从左到右的顺序求值,但赋值目标的处理、短路逻辑和生成器表达式有各自规则。

def mark(name):
    print(name)
    return name

result = mark("left") + mark("right")

输出顺序是:

left
right

短路逻辑则可能跳过右侧表达式:

False and mark("never")
True or mark("also never")

这不仅是语法知识,也直接影响条件判断、缓存读取和异常触发。

2. 基础数据结构要按数据约束选择

类型 核心约束 典型用途
list 有序、可变、允许重复 批量数据、队列原型
tuple 有序、不可变 固定结构、记录、键
dict 键到值的映射,保留插入顺序 配置、索引、JSON 数据
set 唯一元素、无索引 去重、集合运算、成员测试
str Unicode 文本 人类可读内容
bytes 不可变字节序列 网络协议、文件和序列化

字典键必须保持稳定的哈希值,因此列表和字典不能直接作为键。11.0 比较相等,在字典和集合中也会按照相等与哈希规则视作同一个键类别。(docs.python.org)

data = {
    "user_id": 42,
    "roles": {"admin", "auditor"},
}

payload = '{"ok": true}'
raw = payload.encode("utf-8")
text = raw.decode("utf-8")

不要把 strbytes 混用。文本需要编码成字节才能写入网络或文件,字节需要根据明确编码才能还原为文本。

3. 迭代器、生成器和惰性计算

可迭代对象能产生迭代器;迭代器每次提供一个元素,并在耗尽时抛出 StopIteration

生成器函数使用 yield,调用时不会立刻执行完整函数体,而是返回生成器对象;每次 next() 才推进到下一个 yield。(docs.python.org)

def numbers():
    print("start")
    yield 1
    print("middle")
    yield 2

it = numbers()

print("created")
print(next(it))
print(next(it))

输出:

created
start
1
middle
2

生成器适合处理无法一次性装入内存的数据:

def read_lines(path: str):
    with open(path, encoding="utf-8") as file:
        for line in file:
            yield line.rstrip("\n")

但惰性并不等于免费:

  • 生成器只降低一次性内存占用;
  • 下游如果调用 list(generator),仍会一次性物化;
  • 生成器内部异常会在迭代阶段而不是创建阶段出现;
  • 文件、数据库游标等资源必须在正确生命周期内关闭。

4. 函数、类和协议

函数学习顺序应是:

  1. 参数绑定;
  2. 返回值;
  3. 作用域;
  4. 高阶函数;
  5. 装饰器;
  6. 上下文管理器;
  7. 异步函数。

类不应先从“继承层次”开始,而应先理解对象协议。Python 中很多行为通过特殊方法实现:

class User:
    def __init__(self, name: str):
        self.name = name

    def __repr__(self) -> str:
        return f"User(name={self.name!r})"

    def __eq__(self, other: object) -> bool:
        return isinstance(other, User) and self.name == other.name

__repr__ 决定调试表示,__eq__ 定义相等关系。若定义相等却没有正确处理哈希,实例放入集合或作为字典键时就可能违反数据结构约束。

上下文管理器则把资源获取与释放绑定起来:

with open("output.txt", "w", encoding="utf-8") as file:
    file.write("hello")

即使 write() 抛出异常,退出 with 块时也会执行关闭逻辑。对象不可达后何时被垃圾回收并不是语言层面的资源释放保证;官方文档明确建议显式关闭文件等外部资源。(docs.python.org)

5. 异常不是返回值的替代品

异常表示当前控制流无法按正常结果继续。

def parse_port(value: str) -> int:
    try:
        port = int(value)
    except ValueError as exc:
        raise ValueError(f"invalid port: {value!r}") from exc

    if not 1 <= port <= 65535:
        raise ValueError("port must be between 1 and 65535")
    return port

这里有三层语义:

  1. int(value) 可能抛出 ValueError
  2. 原始异常通过 from exc 保存为因果链;
  3. 业务层抛出更适合调用者理解的新异常。

错误处理应回答:

  • 哪一层负责记录日志;
  • 哪一层负责重试;
  • 哪一层负责转成 HTTP 状态码;
  • 哪些错误可以恢复;
  • 哪些错误必须终止当前任务。

一个常见错误是:

try:
    do_work()
except Exception:
    pass

它会丢失故障信号,使任务看似成功、数据却已经不完整。捕获异常必须有明确动作,例如转换、补偿、重试、记录后重新抛出,或安全降级。

6. 模块和导入

模块是代码组织单位,也是一个命名空间。模块属性访问本质上是模块命名空间中的查找;模块导入还涉及查找、加载、初始化和缓存。(docs.python.org)

# app/config.py
TIMEOUT = 3

# app/main.py
from .config import TIMEOUT

应理解以下边界:

  • import package.module 导入模块对象;
  • from package.module import name 把名称绑定到当前模块;
  • 导入时会执行模块顶层代码;
  • 导入结果会被缓存,重复导入通常不会重新执行;
  • 循环导入可能访问到“尚未初始化完成”的模块。

因此,模块顶层应尽量只放定义和稳定初始化,不要在导入时执行数据库迁移、启动线程或发起网络请求。


四、类型、测试和工具:把“能运行”变成“可演进”

1. 类型标注是接口描述,不是运行时验证

def total(items: list[int]) -> int:
    return sum(items)

这个标注告诉阅读者和静态检查器:函数期望整数列表并返回整数。它不会自动阻止调用者传入错误对象,也不替代运行时校验。

对外部输入必须显式验证:

def parse_user(payload: dict[str, object]) -> tuple[int, str]:
    user_id = payload.get("id")
    name = payload.get("name")

    if not isinstance(user_id, int):
        raise ValueError("id must be int")
    if not isinstance(name, str) or not name:
        raise ValueError("name must be non-empty string")

    return user_id, name

Python 3.14 的函数注解采用惰性求值机制,函数对象还提供了与注解相关的新属性;这属于版本敏感行为,依赖注解运行时对象的工具应针对 3.14 文档和实际解释器进行验证。(docs.python.org)

2. 测试要覆盖状态和失败路径

一个完整测试至少包含:

  • 正常输入;
  • 边界输入;
  • 非法输入;
  • 外部依赖失败;
  • 重试或超时;
  • 并发取消;
  • 数据库事务回滚。

例如价格计算:

from decimal import Decimal

def calculate_total(
    price: Decimal,
    quantity: int,
) -> Decimal:
    if price < 0:
        raise ValueError("price must not be negative")
    if quantity < 0:
        raise ValueError("quantity must not be negative")
    return price * quantity

测试不应只验证 2 * 3 == 6,还应验证负数被拒绝,并明确金额使用 Decimal 而不是二进制浮点数的业务边界。

3. 工具链的学习顺序

建议掌握:

python -m venv
python -m pip
pytest
ruff 或同类检查器
静态类型检查器
覆盖率工具
调试器与 profiling 工具

工具不是独立目标。每个工具都应服务于一个可验证的问题:

  • 依赖是否可重建;
  • 类型边界是否一致;
  • 异常路径是否覆盖;
  • 热点在哪里;
  • 内存是否持续增长;
  • 并发任务是否泄漏。

五、并发:线程、进程、解释器和协程不是同一种东西

1. 并发与并行

并发表示多个任务在时间上交错推进。

并行表示多个任务在同一时刻使用多个执行单元运行。

一个单核事件循环可以并发处理很多 I/O 任务,但同一时刻仍只能执行一个事件循环任务中的 Python 代码。asyncio 官方文档将它定位为基于 async/await 的并发库,尤其适合 I/O 密集型和高层网络代码。(docs.python.org)

选择模型前先问任务类型:

任务 首选方向
等待网络、磁盘、数据库 异步 I/O 或线程
调用阻塞库 线程池或进程外隔离
纯 Python CPU 计算 进程、解释器池,或专门的原生库
大规模独立批处理 进程池、任务队列
共享可变状态 尽量减少共享,必要时显式同步

2. 线程

线程共享同一进程地址空间,因此传递对象方便,但也带来竞态条件:

import threading

counter = 0

def increase():
    global counter
    for _ in range(100_000):
        counter += 1

threads = [threading.Thread(target=increase) for _ in range(4)]

for thread in threads:
    thread.start()
for thread in threads:
    thread.join()

print(counter)

不能把 counter += 1 理解为不可分割操作。它至少包含读取、计算和写回。多个线程可能读取相同旧值,导致更新丢失。

import threading

counter = 0
lock = threading.Lock()

def increase():
    global counter
    for _ in range(100_000):
        with lock:
            counter += 1

锁保证临界区互斥,但不能自动解决死锁、锁粒度过大和任务饥饿。更好的设计通常是减少共享状态,让线程通过消息或队列传递数据。

3. 进程

进程拥有独立地址空间,通信需要序列化、管道、队列、共享内存或外部服务。它可以绕开传统 CPython 全局解释器锁对多进程的限制,但进程创建和数据传输都有成本。multiprocessing 通过子进程提供与 threading 相似的 API,并支持进程池。(docs.python.org)

from concurrent.futures import ProcessPoolExecutor

def square(value: int) -> int:
    return value * value

if __name__ == "__main__":
    with ProcessPoolExecutor() as pool:
        print(list(pool.map(square, range(5))))

输出:

[0, 1, 4, 9, 16]

必须使用 if __name__ == "__main__": 保护入口,特别是使用 spawn 时,子进程需要重新导入主模块。如果顶层代码直接创建新进程,可能无限递归创建子进程。

Python 3.14 中,ProcessPoolExecutor 默认进程启动方式已不再是 fork;如果确实需要 fork,应显式传入对应的 multiprocessing context。不同平台的默认方式和对全局可变状态的继承行为不同,不能把某个 Linux 环境的行为当成跨平台保证。(docs.python.org)

4. 解释器池

Python 3.14 的 InterpreterPoolExecutor 使用多个解释器,每个解释器运行在线程中,但拥有独立的解释器状态和全局解释器锁,因此可以实现多核并行。不同解释器之间不能直接共享可变 Python 对象,通信通常需要序列化或专用机制。(docs.python.org)

from concurrent.futures import InterpreterPoolExecutor

def compute(value: int) -> int:
    return value * value

if __name__ == "__main__":
    with InterpreterPoolExecutor(max_workers=2) as pool:
        results = list(pool.map(compute, range(6)))
    print(results)

它的关键取舍是:

  • 比线程更适合需要多核的 Python 计算;
  • 比进程少一些进程级隔离成本;
  • 仍然要求任务和参数满足跨解释器传递约束;
  • 不能依赖“共享模块全局变量”来传递状态。

这是 Python 3.14 的版本敏感能力,使用前应验证依赖库是否支持多解释器环境。


六、asyncio:事件循环、协程、Future 和调度

1. 协程对象不是任务

import asyncio

async def fetch() -> str:
    await asyncio.sleep(1)
    return "ok"

coroutine = fetch()
print(type(coroutine))

调用 async def 函数会得到协程对象;它尚未执行函数体。协程对象需要被:

  • await
  • 包装成 Task
  • 交给事件循环运行。

最小完整程序:

import asyncio

async def fetch(name: str, delay: float) -> str:
    await asyncio.sleep(delay)
    return name

async def main() -> None:
    first, second = await asyncio.gather(
        fetch("first", 0.2),
        fetch("second", 0.1),
    )
    print(first, second)

asyncio.run(main())

输出:

first second

两个任务的完成顺序是 second 先完成,但 gather() 按传入顺序返回结果,所以打印顺序仍是 first second

2. 事件循环的状态机

事件循环可以抽象为:

就绪队列 -> 执行协程一步 -> 遇到 await
                         |
                         v
                  等待 I/O 或定时器
                         |
                         v
                    条件满足
                         |
                         v
                      就绪队列

一次循环通常做这些事:

  1. 取出可运行的回调或任务;
  2. 推进任务执行;
  3. 如果任务遇到 await,保存其暂停位置;
  4. 注册 I/O、定时器或 Future 完成条件;
  5. 等待操作系统通知;
  6. 条件满足后把任务重新放入就绪队列。

协作式调度的关键是:任务必须主动让出控制权。

async def bad():
    import time
    time.sleep(5)  # 阻塞整个事件循环

time.sleep() 不会让出事件循环,它会阻塞当前线程。正确写法:

async def good():
    await asyncio.sleep(5)

如果必须调用阻塞函数:

import asyncio
import time

def blocking_work() -> str:
    time.sleep(1)
    return "done"

async def main() -> None:
    result = await asyncio.to_thread(blocking_work)
    print(result)

asyncio.run(main())

这并不会把 CPU 计算神奇地变成并行;它的主要用途是把阻塞调用移出事件循环线程。

3. TaskFuture

Future 表示一个尚未完成的结果容器,状态通常经历:

PENDING -> RUNNING -> FINISHED
                  \-> CANCELLED

Task 是事件循环对协程的调度包装,通常也是 Future 的一种扩展形式。

import asyncio

async def work() -> int:
    await asyncio.sleep(0.1)
    return 42

async def main() -> None:
    task = asyncio.create_task(work())

    print(task.done())   # False
    result = await task
    print(result)        # 42
    print(task.done())   # True

asyncio.run(main())

concurrent.futures.Futureasyncio.Future 名称相同,但属于不同并发体系。前者用于线程池、进程池或解释器池;后者用于事件循环中的异步任务。官方文档明确提醒二者不能混淆。(docs.python.org)

4. 取消、超时和异常

取消不是强制杀死线程,而是向协程注入取消信号。协程应在 await 等可中断点处理它。

import asyncio

async def worker() -> None:
    try:
        while True:
            print("working")
            await asyncio.sleep(0.2)
    except asyncio.CancelledError:
        print("cleanup")
        raise

async def main() -> None:
    task = asyncio.create_task(worker())
    await asyncio.sleep(0.5)
    task.cancel()

    try:
        await task
    except asyncio.CancelledError:
        print("cancelled")

asyncio.run(main())

输出可能类似:

working
working
working
cleanup
cancelled

如果捕获 CancelledError 后不重新抛出,调用者可能误以为任务正常完成。因此只有在确实完成清理并有明确语义时才吞掉取消。

超时示例:

import asyncio

async def request() -> str:
    await asyncio.sleep(10)
    return "response"

async def main() -> None:
    try:
        result = await asyncio.wait_for(request(), timeout=1)
        print(result)
    except TimeoutError:
        print("timeout")

asyncio.run(main())

生产代码还必须考虑:

  • 超时后底层操作是否真的停止;
  • 重试是否造成重复写入;
  • 多个任务中一个失败时是否取消其他任务;
  • 取消时连接、文件、锁和临时数据是否释放。

5. 结构化并发

任务应当有清晰的父子生命周期。Python 3.11 起提供的任务组适合表达“这一组任务共同完成一个工作单元”的关系:

import asyncio

async def fetch(name: str) -> str:
    await asyncio.sleep(0.1)
    if name == "bad":
        raise RuntimeError("fetch failed")
    return name

async def main() -> None:
    try:
        async with asyncio.TaskGroup() as group:
            first = group.create_task(fetch("first"))
            bad = group.create_task(fetch("bad"))
    except* RuntimeError as exc:
        print(f"failed: {exc.exceptions[0]}")

asyncio.run(main())

任务组中的异常会影响整个任务组的退出,避免后台任务无人管理。相比随意创建大量 create_task(),结构化生命周期更容易保证异常、取消和资源释放的一致性。

Python 3.14 还为自由线程化 Python 提供了 asyncio 相关支持,但事件循环中的单个任务仍然需要避免长时间运行的同步 Python 代码;一个事件循环在一个核心上可以管理大量连接,但每个请求中的计算仍会占用执行时间。(docs.python.org)


七、Web:从 HTTP 到应用生命周期

1. 先理解 HTTP 数据流

一次典型请求包含:

客户端
  -> TCP/TLS
  -> HTTP 请求行、请求头、请求体
  -> Web 服务器
  -> Python 应用
  -> 路由
  -> 业务逻辑
  -> 数据库或外部服务
  -> HTTP 响应
  -> 客户端

应用不应把所有输入都当成可信数据。至少要验证:

  • HTTP 方法;
  • 路径参数;
  • 查询参数;
  • 请求体结构;
  • 内容类型;
  • 身份和权限;
  • 超时和大小限制。

2. WSGI 与 ASGI

WSGI 是传统同步 Python Web 应用与服务器之间的接口模型。

ASGI 扩展了同步请求模型,能够表达异步 HTTP、WebSocket 和生命周期事件。选择 ASGI 不等于业务代码自动异步;如果在 async def 处理器中调用阻塞数据库驱动或同步 HTTP 客户端,仍会阻塞事件循环。

一个框架的完整生命周期应理解为:

进程启动
 -> 加载配置
 -> 创建连接池
 -> 注册路由和中间件
 -> 接收请求
 -> 解析与验证
 -> 执行业务逻辑
 -> 提交或回滚事务
 -> 返回响应
 -> 进程退出
 -> 关闭连接池

框架只负责一部分生命周期。数据库连接、后台任务、缓存客户端和模型对象是否正确创建、复用和关闭,仍然是应用设计责任。

3. 一个最小 ASGI 应用

不依赖第三方框架也可以理解 ASGI 的基本形状:

from typing import Any

async def application(
    scope: dict[str, Any],
    receive: Any,
    send: Any,
) -> None:
    if scope["type"] != "http":
        return

    await send({
        "type": "http.response.start",
        "status": 200,
        "headers": [(b"content-type", b"text/plain; charset=utf-8")],
    })
    await send({
        "type": "http.response.body",
        "body": b"hello",
    })

ASGI 通过事件消息传递请求和响应,而不是把所有细节固定成单一函数返回值。真实框架会在外层处理路由、请求体、异常、中间件和连接生命周期。

4. Web 业务的错误边界

业务错误不应全部变成 500

错误 常见响应
JSON 格式错误 400
未认证 401
无权限 403
资源不存在 404
请求冲突 409
参数语义非法 422400
未预期程序异常 500

但状态码只是传输层表达。真正重要的是内部是否保留异常因果、请求 ID、用户身份、数据库事务状态和外部调用结果。


八、数据:从内存结构到数据库一致性

1. SQL 不是“把列表存起来”

数据库学习应从关系和约束开始:

  • 表表示关系;
  • 行表示实体或事实;
  • 列表示属性;
  • 主键标识记录;
  • 外键表达引用;
  • 唯一约束表达业务不重复;
  • 检查约束表达局部不变量;
  • 事务表达一组操作的原子边界。

例如订单扣库存:

BEGIN;

UPDATE inventory
SET available = available - 1
WHERE product_id = 100
  AND available >= 1;

-- 检查受影响行数必须为 1
INSERT INTO orders (product_id, user_id)
VALUES (100, 200);

COMMIT;

如果 UPDATE 影响 0 行,说明库存不足或商品不存在,此时不能继续插入订单,应回滚。

事务的核心不是“包住几条 SQL”,而是定义状态转换:

库存 available = n
订单不存在
        |
        | 条件 available >= 1
        v
库存 available = n - 1
订单已创建

如果应用先查库存,再更新库存,而中间没有锁、条件更新或合适的隔离机制,两个请求可能同时读到同一个库存值,形成超卖。

2. ORM 的边界

ORM 适合表达实体关系和常见 CRUD,但不应隐藏:

  • SQL 查询数量;
  • 事务开始和结束;
  • 锁;
  • 延迟加载;
  • 批量操作;
  • 索引使用;
  • 数据库错误。

一个循环中逐条访问关联对象,可能产生 N+1 查询。诊断方法是打开 SQL 日志、检查执行计划,并确认请求一次执行了多少条查询,而不是只看 Python 代码行数。

3. 数据处理路线

数据方向建议按以下顺序:

Python 容器与迭代器
 -> CSV、JSON、文本和二进制
 -> SQL 与事务
 -> NumPy 数组与向量化
 -> DataFrame 与缺失值、分组、连接
 -> ETL / ELT
 -> 数据质量、血缘和调度

数据处理最容易出现的错误不是语法错误,而是语义错误:

  • 时区混乱;
  • 金额用浮点数;
  • 缺失值与零混淆;
  • 字符串数字未转换;
  • 重复记录未定义;
  • 连接键不唯一导致行数膨胀;
  • 统计口径未固定。

学习每个数据工具时,都要回答“输入的模式是什么、输出的模式是什么、缺失数据如何传播、失败后是否可重跑”。


九、AI:从数值计算到可验证的应用系统

AI 不是 Python 语言的一个语法分支,而是建立在数据、数值计算、模型接口和生产服务之上的应用层。

1. 先补齐数学和数据基础

至少需要理解:

  • 向量、矩阵和张量;
  • 线性变换;
  • 概率分布;
  • 损失函数;
  • 梯度下降;
  • 训练集、验证集和测试集;
  • 过拟合;
  • 推理延迟与吞吐量。

一个简单的线性模型:

y^=wx+b\hat{y} = wx + b

其中:

  • xx 是输入;
  • ww 是权重;
  • bb 是偏置;
  • y^\hat{y} 是预测值。

若使用平方损失:

L=12(y^y)2L = \frac{1}{2}(\hat{y} - y)^2

梯度为:

Lw=(y^y)x\frac{\partial L}{\partial w} = (\hat{y} - y)x

Lb=y^y\frac{\partial L}{\partial b} = \hat{y} - y

学习率为 η\eta 时,参数更新为:

wwηLww \leftarrow w - \eta \frac{\partial L}{\partial w}

bbηLbb \leftarrow b - \eta \frac{\partial L}{\partial b}

完整数值算例:

x = 2
y = 10
w = 3
b = 1
η = 0.1

第一步预测:

y^=3×2+1=7\hat{y} = 3 \times 2 + 1 = 7

第二步误差:

e=y^y=710=3e = \hat{y} - y = 7 - 10 = -3

第三步梯度:

Lw=3×2=6\frac{\partial L}{\partial w} = -3 \times 2 = -6

Lb=3\frac{\partial L}{\partial b} = -3

第四步更新:

w=30.1×(6)=3.6w = 3 - 0.1 \times (-6) = 3.6

b=10.1×(3)=1.3b = 1 - 0.1 \times (-3) = 1.3

第五步重新预测:

y^new=3.6×2+1.3=8.5\hat{y}_{new} = 3.6 \times 2 + 1.3 = 8.5

预测从 7 接近了 10。这个例子虽然简单,却说明了“模型、损失、梯度、参数更新”之间的因果链。

2. 训练和推理是不同系统

训练关注:

  • 数据读取;
  • 批处理;
  • 梯度计算;
  • 参数更新;
  • checkpoint;
  • 验证指标;
  • 可复现性。

推理关注:

  • 模型加载;
  • 输入校验;
  • 批量与并发;
  • 延迟;
  • 显存或内存;
  • 超时;
  • 降级;
  • 输出安全。

训练阶段的代码不能直接原样搬到 Web 请求中。模型加载一次还是每请求加载、是否共享只读权重、是否需要进程级副本,都会改变容量和内存模型。

3. LLM 应用的最小闭环

大语言模型应用通常包含:

用户输入
 -> 输入校验与安全过滤
 -> 上下文检索或工具调用
 -> Prompt 组装
 -> 模型推理
 -> 输出解析
 -> 业务校验
 -> 持久化与观测

如果使用检索增强生成,至少要区分:

  • 文档切分;
  • 嵌入生成;
  • 向量检索;
  • 候选重排;
  • 上下文拼接;
  • 模型生成;
  • 引用或证据绑定。

“模型输出看起来合理”不是正确性的证明。应建立评估集,检查:

  • 检索是否找到相关内容;
  • 生成是否引用了上下文;
  • 结构化输出是否符合 schema;
  • 敏感信息是否泄漏;
  • 失败时是否明确拒答;
  • 模型升级后指标是否回归。

AI 应用交付的核心不是把模型接上 API,而是让输入、上下文、模型版本、输出和评估结果可追踪。


十、生产交付:进程模型、容量、配置、迁移、灰度和回滚

1. 进程模型

一个 Python Web 服务通常可以分成:

负载均衡器
   |
多个服务进程
   |
每个进程:
  路由与业务代码
  数据库连接池
  缓存连接
  本地内存缓存
  线程池或事件循环

必须区分:

  • 进程级状态:每个 worker 一份;
  • 线程级状态:同一进程内共享地址空间;
  • 协程级状态:任务之间应通过局部变量或上下文隔离;
  • 外部共享状态:数据库、缓存、消息队列。

如果进程内有本地缓存,多个 worker 之间不会自动同步。一个请求写入 worker A 的缓存,随后请求落到 worker B,可能仍读到旧值。因此一致性要求高的状态应放在共享存储中。

2. 容量估算

对于同步服务,可以用近似关系理解并发:

CR×TC \approx R \times T

其中:

  • CC 是平均在途请求数;
  • RR 是吞吐率,单位为请求/秒;
  • TT 是平均响应时间,单位为秒。

例如:

R = 200 请求/秒
T = 0.25 秒
C ≈ 200 × 0.25 = 50 个在途请求

如果数据库连接池只有 10 个连接,而每个请求都需要占用数据库连接,那么数据库可能成为瓶颈,即使 Web worker 还能接收更多请求。

容量评估不能只看 CPU。还要看:

  • 内存;
  • 数据库连接数;
  • 外部 API 限流;
  • 文件描述符;
  • 事件循环阻塞时间;
  • 队列长度;
  • 单请求数据量;
  • 模型显存或进程内存。

3. 配置

配置应按生命周期和敏感性分类:

配置 示例 处理方式
代码默认值 超时默认值 可进入代码
环境配置 数据库地址 部署注入
密钥 API Key、密码 密钥管理系统
运行时开关 灰度比例 可动态读取或配置中心
数据库结构 表和索引 迁移系统管理

不要把密钥写入源码、镜像层或日志。配置解析应在启动时完成,并对必需项进行失败即停的校验:

import os

def require_env(name: str) -> str:
    value = os.getenv(name)
    if not value:
        raise RuntimeError(f"missing required environment variable: {name}")
    return value

DATABASE_URL = require_env("DATABASE_URL")

启动阶段失败比服务启动后收到第一条请求才失败更容易发现,也更容易阻止错误版本进入流量。

4. 数据库迁移

迁移是对数据库结构的有序状态转换:

Schema v1
  -> migration 001
Schema v2
  -> migration 002
Schema v3

生产迁移必须考虑旧代码和新代码可能同时运行。因此优先使用 扩展—迁移—收缩

  1. 扩展:新增可选列或新表;
  2. 发布兼容代码:同时读写旧字段和新字段;
  3. 回填数据;
  4. 切换读取逻辑;
  5. 删除旧字段。

反例是一次发布同时:

删除旧列
部署只认识新列的代码

如果新代码回滚,而旧代码已经无法访问被删除的列,回滚就不再是应用层可完成的操作。

迁移前应验证:

  • 备份是否存在;
  • 备份是否可以恢复;
  • 迁移在副本数据库上耗时多久;
  • 是否锁表;
  • 是否可重复执行;
  • 失败后数据库处于什么状态;
  • 应用旧版本能否继续运行。

5. 灰度发布

灰度发布不是简单地“把 10% 请求转到新版本”,而是一个带观测和停止条件的状态机:

旧版本 100%
   |
   | 部署新版本,健康检查通过
   v
旧版本 90% / 新版本 10%
   |
   | 错误率、延迟、业务指标正常
   v
旧版本 50% / 新版本 50%
   |
   | 持续验证
   v
新版本 100%

灰度路由可以按:

  • 随机比例;
  • 用户 ID;
  • 租户;
  • 地域;
  • 请求头;
  • 功能开关。

按用户 ID 灰度通常能保持同一用户体验稳定,但需要注意哈希分布和用户迁移。按随机请求灰度可能导致同一用户在两个版本间来回切换。

灰度期间至少观察:

  • 5xx 错误率;
  • P95/P99 延迟;
  • 超时率;
  • 数据库慢查询;
  • 队列积压;
  • 业务成功率;
  • 新旧版本结果差异;
  • 资源使用率。

6. 回滚

回滚有三种不同含义:

  1. 流量回滚:把请求切回旧版本;
  2. 代码回滚:部署旧构建产物;
  3. 数据回滚:恢复或逆向修改数据。

前两者通常较快,数据回滚风险最大。已经提交的业务数据不能简单依靠“撤销部署”恢复。

可靠的发布流程应保存:

构建产物版本
配置版本
数据库迁移版本
依赖锁定信息
灰度指标
回滚命令
验证命令

每个发布动作都要有验证步骤。例如:

# 1. 检查服务健康
curl -fsS http://127.0.0.1:8000/health

# 2. 检查关键业务
curl -fsS http://127.0.0.1:8000/api/version

# 3. 检查日志中是否出现启动错误
journalctl -u example.service --since "5 minutes ago"

命令成功不代表业务正确。curl 返回 HTTP 200,只能说明网络请求和健康接口成功,不能证明数据库写入、消息投递或模型输出正确。


十一、推荐的阶段性学习路线

阶段一:语言核心

目标是能够解释每个表达式和对象变化。

学习内容:

语法与求值
名称、对象、身份、类型和值
可变性与复制
作用域、闭包、参数绑定
函数、类和协议
异常与资源管理
模块与导入
迭代器与生成器

练习重点不是刷题,而是写出对象关系和状态变化。例如:

  • 实现浅复制与深复制对比;
  • 编写带闭包状态的计数器;
  • 实现上下文管理器;
  • 追踪循环导入;
  • 用生成器处理大文件。

阶段二:工程基础

学习:

虚拟环境
依赖管理
日志
配置
测试
类型检查
代码质量检查
调试和性能分析

交付一个命令行项目,要求:

  • 可以从干净环境安装;
  • 有明确入口;
  • 有单元测试;
  • 非法输入有错误信息;
  • 日志不泄露密钥;
  • 依赖和 Python 版本有记录。

阶段三:并发

按以下顺序:

线程与共享状态
锁、条件变量、队列
进程与进程间通信
Executor 与 Future
asyncio 事件循环
协程、Task、取消和超时
结构化并发
阻塞代码的隔离

练习项目可以是一个批量 URL 检查器:

  • 同步版本;
  • 线程池版本;
  • asyncio 版本;
  • 进程池版本;
  • 比较吞吐、错误传播、超时和取消行为。

不要只比较运行时间。要记录:

  • 并发数;
  • 每种 I/O 的等待时间;
  • 失败数量;
  • 超时数量;
  • 内存;
  • 是否有任务泄漏。

阶段四:Web 与数据

实现一个带数据库的服务:

用户注册
 -> 身份验证
 -> 资源创建
 -> 分页查询
 -> 事务更新
 -> 审计日志

要求明确:

  • 请求校验;
  • 错误状态码;
  • 数据库事务;
  • 幂等键;
  • 查询索引;
  • 超时;
  • 健康检查;
  • 日志和请求 ID。

阶段五:AI 应用

先做可评估的小项目:

文本分类
 -> 向量检索
 -> RAG 问答
 -> 结构化输出
 -> 工具调用
 -> Web 服务化

每个阶段都保留固定测试集,记录模型版本、Prompt 版本、检索参数和输出评估结果。否则模型升级后无法判断是模型变化、数据变化还是业务代码变化导致质量波动。

阶段六:生产交付

最后把一个服务完整交付:

构建
 -> 测试
 -> 迁移
 -> 部署
 -> 健康检查
 -> 灰度
 -> 指标观察
 -> 全量
 -> 回滚演练

必须实际演练:

  • 数据库迁移失败;
  • 新版本启动失败;
  • 外部服务超时;
  • 消息重复投递;
  • worker 被杀死;
  • 连接池耗尽;
  • 配置缺失;
  • 模型加载失败;
  • 灰度指标恶化。

十二、用一个纵向项目串起全部知识

可以构建一个“异步数据与 AI 服务”作为贯穿项目:

HTTP API
  |
  +-- 用户与权限
  +-- 任务提交
  +-- 异步任务队列
  +-- 数据库
  +-- 文件对象存储
  +-- 文本切分与向量化
  +-- 检索与模型推理
  +-- 结果查询
  +-- 指标、日志、审计

它能覆盖:

  • Python 名称和对象;
  • 类型标注和异常;
  • 模块边界;
  • asyncio 调度;
  • 线程池隔离阻塞库;
  • 进程或解释器池执行 CPU 任务;
  • HTTP 请求生命周期;
  • 数据库事务;
  • AI 推理;
  • 进程模型与容量;
  • 配置、迁移、灰度和回滚。

最终验收标准不是“接口能返回结果”,而是能够回答:

  1. 请求进入哪个进程和哪个协程?
  2. 等待数据库时事件循环是否被阻塞?
  3. 任务取消时资源是否释放?
  4. 数据库事务在哪一步提交?
  5. 同一任务重复执行是否安全?
  6. 多个 worker 的缓存是否一致?
  7. 模型加载了几份?
  8. 数据库连接池是否会耗尽?
  9. 新旧代码能否共存于迁移期间?
  10. 发布失败后能否只回滚流量而不破坏数据?

能够回答这些问题,才说明已经从“会写 Python”进入“理解 Python 系统”。

Python 3.14 的学习重点仍然不是记住更多 API,而是建立跨层因果链:名称如何指向对象,协程如何被事件循环调度,Web 请求如何穿过进程和连接池,数据如何在事务中改变,模型如何在服务中占用资源,以及一次发布如何安全地改变整个系统。

完整学习目录

一、语言与运行模型

  1. Python 3.14 工具链:安装、解释器、REPL、脚本与版本管理
  2. Python 执行模型:源码、AST、字节码、解释器帧与调用栈
  3. Python 词法与语法基础:缩进、Token、表达式、语句和注释
  4. Python 名称、对象与绑定:变量不是盒子,赋值不是复制
  5. Python 数值类型:int、float、complex、bool 与运算边界
  6. Python 字符串、bytes 与 Unicode:编码、解码和文本边界
  7. Python list、tuple 与 range:存储、切片、复杂度和选择
  8. Python dict 与 set:哈希、顺序、冲突、复杂度和键约束
  9. Python 控制流:if、for、while、break、else 与作用域
  10. Python 结构化模式匹配:match、case、守卫、绑定与陷阱
  11. Python 函数与参数:位置、关键字、默认值、解包和返回
  12. Python 作用域与闭包:LEGB、nonlocal、global 和迟绑定
  13. Python 装饰器:函数包装、参数化、类装饰器与元数据
  14. Python 可迭代对象与迭代器:协议、惰性、耗尽和组合
  15. Python 生成器:yield、send、throw、close 与委托
  16. Python 推导式:列表、集合、字典、生成器与作用域边界
  17. Python 异常体系:传播、链、分组、清理和错误契约
  18. Python 上下文管理器:with、协议、ExitStack 与资源安全
  19. Python 模块与包:命名空间、init、入口和项目边界
  20. Python 导入系统:搜索路径、缓存、Finder、Loader 与循环依赖

二、对象与类型系统

  1. Python 对象模型:type、object、属性查找、身份与生命周期
  2. Python 类与继承:实例、类属性、组合、覆盖和边界
  3. Python MRO 与 super:C3 线性化、多继承和协作调用
  4. Python 描述符与 property:属性访问、绑定方法和 ORM 基础
  5. Python ABC 与 Protocol:名义子类型、结构化类型和接口设计
  6. Python dataclass 与 Enum:数据模型、不可变性、比较和序列化
  7. Python 特殊方法:容器、运算符、调用、表示与上下文协议
  8. Python 元类:类创建流程、prepare、注册和使用边界
  9. Python 反射与自省:inspect、签名、Frame、AST 和安全边界
  10. Python 类型标注基础:Union、Literal、TypedDict、Narrowing 与边界
  11. Python 泛型类型:TypeVar、ParamSpec、TypeVarTuple 与 Protocol
  12. Python 复制与序列化:浅拷贝、深拷贝、pickle 和不可信输入
  13. Python 内存与垃圾回收:引用计数、循环 GC、分代与诊断
  14. Python weakref 与 slots:生命周期观察、对象布局和内存取舍
  15. Python GIL 与自由线程构建:互斥边界、扩展兼容和并行选择

三、标准库与系统编程

  1. Python 文件系统与 pathlib:路径、遍历、元数据、原子替换和竞态
  2. Python I/O 模型:文本、二进制、缓冲、编码和流式处理
  3. Python 结构化数据:JSON、CSV、TOML、Schema 与精度边界
  4. Python 日期时间:datetime、时区、DST、时间戳和序列化
  5. Python 正则表达式:匹配模型、分组、回溯、性能和 Unicode
  6. Python collections:deque、Counter、defaultdict、ChainMap 与队列
  7. Python itertools:惰性组合、无限序列、分组和内存边界
  8. Python functools:缓存、偏函数、归约、分派和装饰器工具
  9. Python Decimal 与 Fraction:精度、舍入、上下文和金融计算
  10. Python 随机数与 secrets:伪随机、采样、种子和密码学边界
  11. Python 子进程与信号:参数传递、管道、超时、退出和回收
  12. Python 日志工程:Logger、Handler、结构化字段、上下文和轮转
  13. Python 配置管理:环境变量、文件、校验、Secret 与多环境
  14. Python CLI 工程:argparse、子命令、退出码、管道和可测试性

四、并发、异步与网络

  1. Python asyncio 完整基础:事件循环、协程、Future 与调度
  2. Python 异步任务:create_task、TaskGroup、异常组和结构化并发
  3. Python asyncio 网络流:TCP、Reader、Writer、TLS 与背压
  4. Python asyncio 取消与同步:Timeout、Lock、Queue 和清理
  5. Python 线程:生命周期、锁、条件变量、竞态和死锁诊断
  6. Python 多进程:启动方式、IPC、共享内存、Pool 与回收
  7. Python concurrent.futures:线程池、进程池、Future 和取消
  8. Python 队列与背压:queue、asyncio.Queue、容量和关闭协议
  9. Python Socket 编程:TCP、UDP、地址、半关闭、超时和协议帧
  10. Python HTTP 客户端:连接池、超时、重试、流式和 TLS
  11. Python 哈希、HMAC 与 TLS:完整性、密码存储、证书和误区

五、工程质量与包管理

  1. Python pyproject.toml:构建系统、项目元数据、入口和工具配置
  2. Python 虚拟环境:venv、解释器隔离、路径和常见污染
  3. Python 依赖解析与锁定:版本约束、Lock、哈希和供应链
  4. Python 包构建与发布:wheel、sdist、索引、签名和版本
  5. Python 代码质量:Ruff、格式化、Lint、导入排序和规则治理
  6. Python pytest 完整基础:Fixture、参数化、标记、插件和隔离
  7. Python unittest 与 Mock:替身边界、Patch、异步和脆弱测试
  8. Python 属性测试:Hypothesis、生成策略、缩减和状态机测试
  9. Python 静态类型工程:mypy、Pyright、Stub、渐进迁移和 CI
  10. Python 调试:pdb、断点、异常现场、日志和远程诊断
  11. Python 性能剖析:timeit、cProfile、tracemalloc、采样和证据链
  12. Python 基准测试:预热、噪声、统计、pyperf 和回归判断
  13. Python 安全工程:输入、注入、反序列化、依赖、Secret 和沙箱
  14. Python 应用架构:模块边界、依赖方向、领域层和可替换适配器

六、Web、数据与服务开发

  1. FastAPI 完整基础:路由、依赖注入、校验、异步和生命周期
  2. Pydantic v2:模型、校验器、序列化、Settings 和性能边界
  3. Flask 完整基础:应用工厂、Context、Blueprint、扩展和部署
  4. Django 完整基础:项目、请求链、模型、模板、Admin 和安全
  5. Django REST Framework:Serializer、ViewSet、权限、分页和限流
  6. Python WSGI 与 ASGI:调用协议、并发模型、中间件和部署选择
  7. Python Web API 工程:契约、错误、分页、幂等、限流和版本
  8. SQLAlchemy 2.0:Engine、Session、映射、查询、事务和 N+1
  9. Alembic 数据库迁移:Revision、自动生成、分支、上线和回滚
  10. Python 异步数据库访问:连接池、事务、取消、并发和一致性
  11. Python 与 Redis:连接池、Pipeline、事务、缓存和分布式锁
  12. Celery 任务队列:Broker、Worker、ACK、重试、定时和幂等
  13. Python 消息系统:RabbitMQ、Kafka、消费语义、重试和死信
  14. Python gRPC:Protobuf、流式调用、Deadline、拦截器和错误模型
  15. Python 实时通信:WebSocket、SSE、心跳、广播和背压
  16. Python Web 认证与授权:Session、JWT、OAuth 2.0、RBAC 和 CSRF
  17. Python 文件上传与后台处理:流式、校验、对象存储和任务状态
  18. Python 网络采集:Requests、HTTPX、BeautifulSoup、限速和合规

七、数据、AI 与桌面开发

  1. NumPy 完整基础:ndarray、形状、广播、索引、向量化和内存布局
  2. pandas 完整基础:Series、DataFrame、索引、缺失值、分组和连接
  3. Python 数据可视化:Matplotlib、Seaborn、坐标、布局和可解释图表
  4. scikit-learn 工程基础:Pipeline、预处理、训练、评测和持久化
  5. Python PyTorch 工程:Tensor、Autograd、Dataset、训练和检查点
  6. Jupyter 工程化:Kernel、Notebook 状态、复现、参数化和安全
  7. Python OpenAI SDK:Responses、流式、结构化输出、工具和重试
  8. Python Agent 框架选型:原生循环、Agents SDK、LangGraph 和 PydanticAI
  9. Python Tkinter GUI:事件循环、布局、控件、线程和打包
  10. Python PySide 与 Qt:信号槽、Model/View、线程、资源和发布
  11. Python 自动化脚本:文件、命令、网络、重试、幂等和审计
  12. Python 定时任务:时间语义、调度器、重复执行、锁和补偿

八、性能、交付与生产治理

  1. Python 国际化:gettext、Locale、日期数字、消息目录和回退
  2. Python 可观测性:日志、指标、Trace、Context 和故障定位
  3. Python 集成测试:Testcontainers、数据库、消息队列和稳定隔离
  4. Python 原生扩展与性能:C API、Cython、PyO3、ABI 和边界
  5. Python 实验可复现:随机种子、环境、数据、制品和运行记录
  6. Python 容器与 CI:镜像、依赖缓存、测试、制品和供应链
  7. Python 生产交付:进程模型、容量、配置、迁移、灰度和回滚

系列导航与关联阅读

官方资料

本文依据 Python 官方文档、相关 PEP 与生态项目官方文档重新梳理;正文、示例与工程清单由 WR BLOG 编写。