外观
Python 系统学习文档
适合人群:已经掌握 JavaScript/TypeScript,准备学习 Python 后端、AI 应用开发、数据处理、LangChain/LangGraph、FastAPI 或自动化脚本的学习者。
学习目标:从 Python 基础语法入门,逐步掌握函数、模块、面向对象、类型标注、虚拟环境、包管理、异常、文件处理、异步、测试、FastAPI、数据处理和 AI 工程实践。
核对时间:2026-09-01。Python 官方当前稳定文档为 Python 3.14.7,Python 3.15 仍处于预发布文档阶段。学习和项目开发应优先使用稳定版本。
官方资料:
- Python 官方文档:https://docs.python.org/3/
- Python Tutorial:https://docs.python.org/3/tutorial/
- Python Library Reference:https://docs.python.org/3/library/
- Python Packaging User Guide:https://packaging.python.org/
- FastAPI 文档:https://fastapi.tiangolo.com/
目录
第一篇:Python 基础
- Python 是什么
- 安装与运行
- 基本语法
- 数据类型
- 条件和循环
- 函数
第二篇:核心语言能力
- list、tuple、dict、set
- 字符串处理
- 解包、推导式和切片
- 异常处理
- 模块和包
- 面向对象
- dataclass 和 enum
第三篇:工程化基础
- 虚拟环境
- pip、requirements 和 pyproject
- 类型标注
- 文件和路径
- JSON、时间和日志
- 测试
- 代码风格和格式化
第四篇:后端与 AI 工程
- 同步和异步
- FastAPI 基础
- Pydantic
- HTTP 请求
- 数据处理
- Python AI 生态
- LangChain/LangGraph 项目实践
第五篇:进阶
- 迭代器和生成器
- 装饰器
- 上下文管理器
- 并发和多进程
- 性能优化
- 常见误区和学习路线
- 核心知识点深度补全
第一篇:Python 基础
1. Python 是什么
Python 是一门简洁、动态类型、解释型语言,广泛用于:
- AI 应用开发
- 数据分析
- 自动化脚本
- Web 后端
- 爬虫
- 科学计算
- 运维工具
对前端开发者来说,Python 最大价值在 AI 方向:
- LangChain、LangGraph 生态成熟。
- 数据处理库丰富。
- 模型、向量库、Embedding、RAG 示例大多优先支持 Python。
- FastAPI 适合快速搭建 AI 服务。
2. 安装与运行
查看版本:
bash
python --version运行文件:
bash
python main.py交互模式:
bash
python第一个程序:
python
print("Hello Python")注意:Windows 上可能需要使用 py 或 python3,具体看本机安装方式。
3. 基本语法
Python 使用缩进表示代码块。
python
age = 18
if age >= 18:
print("adult")
else:
print("minor")和 JavaScript 不同:
- 不用分号。
- 不用花括号。
- 缩进有语义。
- 变量无需声明类型。
None类似 JS 中的null。
注释:
python
# 单行注释4. 数据类型
常见类型:
python
name = "Alice" # str
age = 18 # int
price = 19.99 # float
active = True # bool
empty = None # NoneType容器:
python
names = ["Alice", "Bob"] # list
point = (10, 20) # tuple
user = {"name": "Alice"} # dict
tags = {"ai", "python"} # setPython 是动态类型,但不是无类型。每个值都有明确类型,只是变量名不固定绑定某个类型。
5. 条件和循环
if:
python
if score >= 90:
level = "A"
elif score >= 60:
level = "B"
else:
level = "C"for:
python
for name in names:
print(name)while:
python
while count < 10:
count += 1遍历索引和值:
python
for index, name in enumerate(names):
print(index, name)6. 函数
定义函数:
python
def add(a, b):
return a + b带类型标注:
python
def add(a: int, b: int) -> int:
return a + b默认参数:
python
def greet(name: str = "Guest") -> str:
return f"Hello {name}"关键字参数:
python
greet(name="Alice")注意:可变默认参数是常见坑。
不要这样:
python
def append_item(item, items=[]):
items.append(item)
return items推荐:
python
def append_item(item, items=None):
if items is None:
items = []
items.append(item)
return items第二篇:核心语言能力
7. list、tuple、dict、set
list:
python
items = [1, 2, 3]
items.append(4)tuple:
python
point = (10, 20)dict:
python
user = {"id": 1, "name": "Alice"}
print(user["name"])安全读取:
python
name = user.get("name", "Unknown")set:
python
tags = {"python", "ai"}
tags.add("rag")选择:
- 有序列表:list。
- 不可变组合:tuple。
- 键值映射:dict。
- 去重集合:set。
8. 字符串处理
f-string:
python
name = "Alice"
message = f"Hello {name}"常用:
python
text.strip()
text.lower()
text.upper()
text.split(",")
",".join(items)
text.replace("old", "new")多行字符串:
python
prompt = """
你是一个 AI 助手。
请根据资料回答问题。
"""Prompt 编写中,多行字符串非常常用。
9. 解包、推导式和切片
解包:
python
a, b = (1, 2)列表推导式:
python
squares = [x * x for x in numbers]过滤:
python
active_users = [u for u in users if u["active"]]切片:
python
items[0:10]
items[:10]
items[-1]这些语法能让 Python 代码非常简洁,但不要为了炫技写得难读。
10. 异常处理
python
try:
result = service.run()
except ValueError as exc:
print(f"参数错误: {exc}")
except Exception as exc:
print(f"未知错误: {exc}")
finally:
cleanup()主动抛出:
python
raise ValueError("参数不能为空")建议:
- 不要吞掉异常。
- 日志中保留错误上下文。
- API 层把异常转换成清晰响应。
- AI 工具调用中要把错误结构化返回。
11. 模块和包
模块就是 .py 文件。
python
# math_utils.py
def add(a, b):
return a + b导入:
python
from math_utils import add包是包含多个模块的目录,通常有:
text
app/
├── __init__.py
├── services.py
└── models.py现代 Python 中 __init__.py 不是所有情况都必须,但保留它通常能让包结构更明确。
12. 面向对象
python
class User:
def __init__(self, name: str):
self.name = name
def greet(self) -> str:
return f"Hello {self.name}"使用:
python
user = User("Alice")
print(user.greet())Python 的面向对象比 Java 更灵活,但大型项目仍然需要清晰边界。
AI 工程中常见类:
- ModelClient
- VectorStoreService
- DocumentIngestor
- AgentRunner
- EvaluationService
13. dataclass 和 enum
dataclass:
python
from dataclasses import dataclass
@dataclass
class User:
id: int
name: strenum:
python
from enum import Enum
class OrderStatus(str, Enum):
pending = "pending"
paid = "paid"
cancelled = "cancelled"在 API 和结构化输出中,枚举能减少字符串拼写错误。
第三篇:工程化基础
14. 虚拟环境
虚拟环境用于隔离项目依赖。
创建:
bash
python -m venv .venv激活 Windows:
bash
.venv\Scripts\activate激活 macOS/Linux:
bash
source .venv/bin/activate为什么需要虚拟环境:
- 不污染全局 Python。
- 不同项目可以使用不同依赖版本。
- 方便部署和复现。
15. pip、requirements 和 pyproject
安装依赖:
bash
pip install fastapi uvicorn导出:
bash
pip freeze > requirements.txt安装:
bash
pip install -r requirements.txt现代项目越来越多使用 pyproject.toml 统一描述项目元数据、依赖和工具配置。
常见工具:
- pip
- uv
- poetry
- hatch
- pdm
入门阶段先掌握 venv + pip,工程阶段再学习 uv 或 poetry。
16. 类型标注
python
def greet(name: str) -> str:
return f"Hello {name}"集合类型:
python
def total(values: list[int]) -> int:
return sum(values)可选类型:
python
def find_user(id: int) -> User | None:
...类型标注不会自动阻止运行时错误,但能提升 IDE 提示、静态检查和团队协作质量。
常见工具:
- mypy
- pyright
- ruff
17. 文件和路径
推荐使用 pathlib。
python
from pathlib import Path
path = Path("data") / "input.txt"
content = path.read_text(encoding="utf-8")写文件:
python
path.write_text("hello", encoding="utf-8")读取目录:
python
for file in Path("docs").glob("*.md"):
print(file)RAG 文档导入、日志处理、批处理脚本都会大量用到文件操作。
18. JSON、时间和日志
JSON:
python
import json
data = json.loads(text)
text = json.dumps(data, ensure_ascii=False)时间:
python
from datetime import datetime, timezone
now = datetime.now(timezone.utc)日志:
python
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info("started")生产项目不要只用 print,要使用 logging。
19. 测试
pytest:
python
def add(a: int, b: int) -> int:
return a + b
def test_add():
assert add(1, 2) == 3运行:
bash
pytestAI 应用测试:
- 普通函数用单元测试。
- Prompt 输出用评估集。
- RAG 检索用固定问题集。
- Agent 工具用 mock。
20. 代码风格和格式化
常见工具:
- ruff:lint 和格式化。
- black:格式化。
- isort:导入排序。
- mypy/pyright:类型检查。
- pytest:测试。
推荐命令:
bash
ruff check .
ruff format .
pytestPython 工程质量来自:
- 明确项目结构。
- 类型标注。
- 自动格式化。
- 单元测试。
- 日志和配置管理。
第四篇:后端与 AI 工程
21. 同步和异步
同步:
python
def fetch_data():
return requests.get(url).json()异步:
python
async def fetch_data():
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.json()异步适合:
- 网络 I/O
- 数据库 I/O
- 多个模型/API 并发请求
不要为了异步而异步。CPU 密集任务不一定适合 asyncio。
22. FastAPI 基础
安装:
bash
pip install fastapi uvicorn示例:
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
def health():
return {"status": "ok"}运行:
bash
uvicorn main:app --reloadFastAPI 优势:
- 类型标注驱动。
- 自动生成 OpenAPI。
- 与 Pydantic 集成。
- 适合 AI 服务 API。
23. Pydantic
Pydantic 用于数据校验和序列化。
python
from pydantic import BaseModel
class ChatRequest(BaseModel):
message: str
session_id: strFastAPI 中:
python
@app.post("/chat")
def chat(request: ChatRequest):
return {"reply": request.message}Pydantic 对 AI 工程很重要:
- 校验 API 输入。
- 定义结构化输出。
- 定义 Agent 状态。
- 定义工具参数。
24. HTTP 请求
同步:
python
import requests
response = requests.get("https://api.example.com")
data = response.json()异步:
python
import httpx
async with httpx.AsyncClient() as client:
response = await client.get("https://api.example.com")调用模型 API、业务 API、检索服务都会用到 HTTP。
要处理:
- timeout
- retry
- status code
- error response
- rate limit
25. 数据处理
常用库:
- pandas
- numpy
- pydantic
- pathlib
- json
- csv
CSV:
python
import csv
with open("data.csv", newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
rows = list(reader)pandas:
python
import pandas as pd
df = pd.read_csv("data.csv")
summary = df.groupby("category")["amount"].sum()AI 项目中常见数据处理:
- 文档清洗
- 表格转文本
- 日志分析
- 评估结果统计
26. Python AI 生态
常见方向:
- LLM 应用:LangChain、LangGraph、LlamaIndex
- API 服务:FastAPI
- 数据处理:pandas、numpy
- 向量库:Chroma、FAISS、Milvus、Qdrant
- 模型调用:各模型 SDK
- 评估:RAGAS、自定义 eval、LangSmith
- 部署:Docker、Uvicorn、Gunicorn
前端 AI 全栈不一定要训练模型,但要会:
- 调模型
- 做 RAG
- 写工具
- 做 Agent 状态
- 暴露 API
- 接前端流式 UI
27. LangChain/LangGraph 项目实践
结构:
text
ai-service/
├── app/
│ ├── api/
│ ├── agents/
│ ├── graphs/
│ ├── retrievers/
│ ├── tools/
│ ├── schemas/
│ └── services/
├── tests/
└── pyproject.toml推荐学习项目:
text
文档问答服务
- FastAPI 提供 /chat
- LangChain 做 RAG
- LangGraph 做审批型长任务
- PostgreSQL/pgvector 保存向量
- 前端 Nuxt 展示流式回答和引用来源第五篇:进阶
28. 迭代器和生成器
迭代器:
python
for item in items:
...生成器:
python
def count_up_to(n):
i = 0
while i < n:
yield i
i += 1生成器适合:
- 大文件逐行处理。
- 流式数据。
- 避免一次性加载全部内容。
LLM streaming 也可以用生成器思想理解。
29. 装饰器
装饰器用于包装函数。
python
def log_time(func):
def wrapper(*args, **kwargs):
print("start")
result = func(*args, **kwargs)
print("end")
return result
return wrapper
@log_time
def run():
print("running")常见用途:
- 日志
- 鉴权
- 缓存
- 重试
- 路由注册
FastAPI 的 @app.get 就是装饰器。
30. 上下文管理器
python
with open("a.txt", encoding="utf-8") as f:
content = f.read()with 会自动释放资源。
适合:
- 文件
- 数据库连接
- 网络连接
- 临时资源
- trace/span
异步上下文:
python
async with httpx.AsyncClient() as client:
...31. 并发和多进程
Python 常见并发方式:
- threading:线程。
- multiprocessing:多进程。
- asyncio:异步 I/O。
- concurrent.futures:统一接口。
选择:
- 网络 I/O:asyncio。
- 简单并发任务:ThreadPoolExecutor。
- CPU 密集:ProcessPoolExecutor 或专门计算框架。
AI 应用中多数瓶颈是网络 I/O,例如模型 API、向量库、外部服务,因此 asyncio 很常用。
32. 性能优化
优先级:
- 找到瓶颈。
- 减少不必要 I/O。
- 缓存重复计算。
- 批量处理。
- 异步并发。
- 使用更合适的数据结构。
- 必要时使用原生扩展或专门系统。
不要一开始就微优化。AI 应用中更常见的问题是:
- Prompt 太长。
- 检索太慢。
- 模型太贵。
- 串行调用太多。
- 没有缓存。
33. 常见误区和学习路线
误区一:Python 简单,所以不需要工程化。
纠正:Python 写脚本容易,写长期维护的服务仍然需要结构、测试、类型和日志。
误区二:AI 开发等于训练模型。
纠正:大多数 AI 全栈岗位更需要模型调用、RAG、Agent、数据处理和产品落地。
误区三:动态类型就不用类型标注。
纠正:类型标注能显著提升大型 Python 项目可维护性。
学习路线:
- 基础语法和数据结构。
- 函数、模块、异常。
- 类型标注和 dataclass。
- venv、pip、pyproject。
- 文件、JSON、日志。
- pytest 和 ruff。
- FastAPI 和 Pydantic。
- asyncio 和 httpx。
- LangChain/LangGraph。
- RAG、向量库和评估。
34. 核心知识点深度补全
本章补全 Python 学习中最容易被轻描淡写的部分:数据结构、迭代协议、生成器、装饰器、上下文管理器、类型标注、GIL、线程/进程/协程与 asyncio。目标是让你不仅会写脚本,还能写可维护的 AI 服务和后端工程代码。
34.1 list、tuple、dict、set 的选择
| 类型 | 是否可变 | 是否有序 | 典型用途 |
|---|---|---|---|
list | 可变 | 有序 | 动态列表、队列、小规模数据处理 |
tuple | 不可变 | 有序 | 固定结构、函数多返回值、不可变记录 |
dict | 可变 | 保持插入顺序 | key-value 映射、JSON 对象、配置 |
set | 可变 | 不保证业务顺序 | 去重、成员判断、集合运算 |
frozenset | 不可变 | 不保证业务顺序 | 可作为 dict key 的集合 |
list 适合按顺序存储:
python
users = ["Alice", "Bob"]
users.append("Cindy")
print(users[0])tuple 适合表达固定结构:
python
point = (10, 20)
x, y = pointdict 是 Python 工程中最常见的数据结构:
python
user = {
"id": 1,
"name": "Alice",
"roles": ["admin"],
}
print(user.get("name"))set 适合成员判断:
python
allowed_roles = {"admin", "editor"}
if "admin" in allowed_roles:
print("ok")34.2 可变对象与引用陷阱
Python 变量保存的是对象引用,不是对象本身。
python
a = [1, 2]
b = a
b.append(3)
print(a) # [1, 2, 3]函数默认参数陷阱:
python
def add_item(item, items=[]):
items.append(item)
return items
print(add_item("a")) # ["a"]
print(add_item("b")) # ["a", "b"],不是你想要的正确写法:
python
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items浅拷贝与深拷贝:
python
import copy
users = [{"name": "Alice"}]
shallow = users.copy()
deep = copy.deepcopy(users)
shallow[0]["name"] = "Bob"
print(users[0]["name"]) # Bob
deep[0]["name"] = "Cindy"
print(users[0]["name"]) # Bob34.3 dict 的常见工程写法
合并字典:
python
base = {"timeout": 3, "retries": 2}
override = {"timeout": 10}
config = base | override
print(config) # {"timeout": 10, "retries": 2}安全读取嵌套字段:
python
payload = {"user": {"profile": {"name": "Alice"}}}
name = payload.get("user", {}).get("profile", {}).get("name")统计频率:
python
from collections import Counter
words = ["vue", "python", "vue", "ai"]
counter = Counter(words)
print(counter.most_common(2))按 key 分组:
python
from collections import defaultdict
orders = [
{"user_id": 1, "amount": 100},
{"user_id": 1, "amount": 50},
{"user_id": 2, "amount": 80},
]
groups = defaultdict(list)
for order in orders:
groups[order["user_id"]].append(order)34.4 迭代协议
可迭代对象实现 __iter__,迭代器实现 __iter__ 和 __next__。
python
items = [1, 2, 3]
iterator = iter(items)
print(next(iterator)) # 1
print(next(iterator)) # 2
print(next(iterator)) # 3for 循环本质上就是不断调用 iter() 和 next(),直到捕获 StopIteration。
自定义迭代器:
python
class Countdown:
def __init__(self, start: int):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
value = self.current
self.current -= 1
return value
for number in Countdown(3):
print(number)更推荐用生成器简化:
python
def countdown(start: int):
while start > 0:
yield start
start -= 134.5 生成器与惰性计算
生成器函数遇到 yield 会暂停,把值交给调用方;下次继续从暂停处执行。
python
def read_lines(path: str):
with open(path, "r", encoding="utf-8") as file:
for line in file:
yield line.strip()优点:
- 不需要一次性把所有数据加载到内存。
- 适合处理大文件、流式响应、模型输出流。
- 可以和管道式处理组合。
生成器表达式:
python
squares = (x * x for x in range(1_000_000))
print(next(squares))列表推导式会立即创建完整列表:
python
squares = [x * x for x in range(1_000_000)]AI streaming 场景:
python
def stream_tokens(text: str):
for token in text.split():
yield token
for token in stream_tokens("hello streaming world"):
print(token)34.6 装饰器:函数包装与元数据保留
装饰器本质是“接收函数,返回新函数”的高阶函数。
python
def log_call(func):
def wrapper(*args, **kwargs):
print(f"calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_call
def add(a, b):
return a + b等价于:
python
add = log_call(add)生产代码应使用 functools.wraps 保留原函数元数据:
python
from functools import wraps
def log_call(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"calling {func.__name__}")
return func(*args, **kwargs)
return wrapper带参数装饰器:
python
from functools import wraps
from time import perf_counter
def timer(name: str):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = perf_counter()
try:
return func(*args, **kwargs)
finally:
cost = perf_counter() - start
print(f"{name} cost {cost:.3f}s")
return wrapper
return decorator
@timer("load_user")
def load_user(user_id: int):
return {"id": user_id}常见用途:
- 日志。
- 权限校验。
- 重试。
- 缓存。
- 计时。
- Web 框架路由注册,例如 FastAPI 的
@app.get。
34.7 上下文管理器
上下文管理器用于管理资源的进入和退出,典型语法是 with。
python
with open("data.txt", "r", encoding="utf-8") as file:
content = file.read()无论中间是否抛异常,文件都会被关闭。
自定义上下文管理器:
python
class ManagedResource:
def __enter__(self):
print("open")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("close")
return False # 不吞异常
with ManagedResource() as resource:
print("use")使用 contextlib:
python
from contextlib import contextmanager
@contextmanager
def managed_resource():
print("open")
try:
yield "resource"
finally:
print("close")
with managed_resource() as resource:
print(resource)常见用途:
- 文件。
- 数据库连接和事务。
- 临时目录。
- 锁。
- 测试中的 mock patch。
34.8 类型标注不是运行时类型检查
类型标注主要服务于 IDE、静态检查、协作维护,不会自动阻止运行时传错类型。
python
def add(a: int, b: int) -> int:
return a + b
print(add("1", "2")) # 运行时仍可执行,结果是 "12"常用写法:
python
from typing import TypedDict, Literal, Protocol
type UserId = int
class User(TypedDict):
id: UserId
name: str
role: Literal["admin", "editor", "viewer"]
class Sender(Protocol):
def send(self, message: str) -> None:
...Protocol 适合表达结构化接口:
python
def notify(sender: Sender, message: str) -> None:
sender.send(message)工程建议:
- 函数边界加类型。
- 复杂 dict 用
TypedDict或 Pydantic model。 - 公共模块开启 mypy/pyright 检查。
- 不要为了类型体操牺牲可读性。
34.9 GIL:全局解释器锁
CPython 中有 GIL(Global Interpreter Lock),同一时刻通常只有一个线程执行 Python 字节码。它不代表 Python 不能并发,而是影响 CPU 密集型多线程的并行能力。
适合线程的场景:
- 网络请求。
- 文件 I/O。
- 数据库调用。
- 等待外部服务。
不适合用普通线程加速的场景:
- 大量纯 Python CPU 计算。
- 图片/音频/文本大规模计算。
- 大型循环中的数学运算。
选择:
| 任务类型 | 推荐 |
|---|---|
| I/O 密集,代码简单 | ThreadPoolExecutor |
| I/O 密集,连接数多 | asyncio + async HTTP/DB 客户端 |
| CPU 密集 | ProcessPoolExecutor、原生扩展、专门计算框架 |
| Web API 服务 | FastAPI/Starlette 等异步框架 |
线程池示例:
python
from concurrent.futures import ThreadPoolExecutor
def fetch(url: str) -> str:
return f"content of {url}"
urls = ["https://example.com/a", "https://example.com/b"]
with ThreadPoolExecutor(max_workers=8) as executor:
results = list(executor.map(fetch, urls))进程池示例:
python
from concurrent.futures import ProcessPoolExecutor
def compute(n: int) -> int:
return sum(i * i for i in range(n))
with ProcessPoolExecutor() as executor:
results = list(executor.map(compute, [1_000_000, 2_000_000]))34.10 asyncio 的执行模型
asyncio 是单线程事件循环模型,适合高并发 I/O。关键概念:
| 概念 | 含义 |
|---|---|
| coroutine | 协程对象,由 async 函数调用产生 |
| event loop | 事件循环,调度协程和 I/O |
| task | 被事件循环调度的协程包装 |
| await | 暂停当前协程,把控制权还给事件循环 |
| gather | 并发等待多个 awaitable |
基础示例:
python
import asyncio
async def fetch_user(user_id: int) -> dict:
await asyncio.sleep(1)
return {"id": user_id}
async def main():
user = await fetch_user(1)
print(user)
asyncio.run(main())并发执行:
python
async def main():
users = await asyncio.gather(
fetch_user(1),
fetch_user(2),
fetch_user(3),
)
print(users)串行陷阱:
python
async def slow():
a = await fetch_user(1)
b = await fetch_user(2)
return a, b并发写法:
python
async def fast():
task_a = asyncio.create_task(fetch_user(1))
task_b = asyncio.create_task(fetch_user(2))
return await task_a, await task_b34.11 asyncio 取消、超时与限流
超时:
python
async def main():
try:
result = await asyncio.wait_for(fetch_user(1), timeout=0.5)
except asyncio.TimeoutError:
result = None
print(result)限流:
python
import asyncio
semaphore = asyncio.Semaphore(5)
async def limited_fetch(user_id: int):
async with semaphore:
return await fetch_user(user_id)取消:
python
async def main():
task = asyncio.create_task(fetch_user(1))
task.cancel()
try:
await task
except asyncio.CancelledError:
print("cancelled")工程注意:
- async 函数里不要调用长时间阻塞的同步函数。
- 选择支持 async 的 HTTP/数据库客户端,例如 httpx async client、asyncpg 等。
- 每个外部服务都要有限流和超时。
- 被取消的协程要正确释放资源。
34.12 FastAPI 与 asyncio 的关系
FastAPI 支持同步和异步路由:
python
@app.get("/sync")
def sync_api():
return {"ok": True}
@app.get("/async")
async def async_api():
return {"ok": True}如果路由内部主要是异步 I/O,使用 async def:
python
@app.get("/users/{user_id}")
async def get_user(user_id: int):
data = await user_client.fetch_user(user_id)
return data如果内部调用的是阻塞 SDK,不要简单套一层 async:
python
@app.get("/bad")
async def bad():
result = blocking_sdk.call() # 会阻塞事件循环
return result可以:
- 使用 SDK 的异步版本。
- 把阻塞调用放到线程池。
- 在服务架构上隔离慢任务。
34.13 dataclass、Pydantic 与业务模型
dataclass 适合纯 Python 内部数据结构:
python
from dataclasses import dataclass
@dataclass(frozen=True)
class User:
id: int
name: strPydantic 适合 API 入参、配置、外部数据校验:
python
from pydantic import BaseModel, Field
class CreateUserRequest(BaseModel):
name: str = Field(min_length=1, max_length=50)
age: int = Field(ge=0, le=150)选择:
- 内部计算模型:
dataclass。 - API 边界和外部输入:Pydantic。
- 简单临时结构:dict。
- 复杂业务实体:普通 class 或领域模型。
34.14 Python 工程代码质量清单
- 函数是否有明确输入输出。
- 公共函数是否有类型标注。
- 可变默认参数是否避免。
- 外部 I/O 是否有超时。
- 并发请求是否有限流。
- 异常是否带上下文日志。
- dict 结构是否过深,是否需要模型。
- 大文件是否流式处理。
- 测试是否覆盖成功、失败、边界。
- 依赖是否锁定版本并隔离虚拟环境。
35. 语言机制深度补全
本章补全 Python 里「知道怎么用但不知其所以然」的语言机制:作用域与闭包、参数传递语义、面向对象进阶、字符串与字节编码、导入机制。理解这些能让 AI 服务和后端代码更可靠,也能快速定位那些「玄学 bug」。
35.1 作用域:LEGB 规则
Python 查找名字时按 LEGB 顺序:
text
L(Local) 函数内部
E(Enclosing) 外层函数(闭包)
G(Global) 模块全局
B(Builtin) 内建名称(print、len 等)python
x = "global"
def outer():
x = "enclosing"
def inner():
print(x) # 依次查 inner -> outer -> global -> builtin
inner()
outer() # enclosing在函数内「读」外层变量没问题,但「赋值」会默认创建局部变量:
python
count = 0
def increment():
count = count + 1 # UnboundLocalError原因:函数体内对 count 赋值,Python 把它当作局部变量,但右侧读取时局部变量还没定义。
需要修改外层变量时显式声明:
python
count = 0
def increment():
global count # 声明修改模块级变量
count += 1
def outer():
n = 0
def inner():
nonlocal n # 声明修改外层函数的变量
n += 1
inner()
return n工程建议:global 尽量少用(可维护性差),闭包中用 nonlocal 时也要克制 —— 大量可变闭包状态会让逻辑难追踪。
35.2 闭包与延迟绑定
闭包是「捕获了外层作用域变量的函数」。经典陷阱是循环中的延迟绑定:
python
callbacks = []
for i in range(3):
callbacks.append(lambda: i)
print([f() for f in callbacks]) # [2, 2, 2],不是 [0, 1, 2]原因:lambda 捕获的是变量 i 本身,循环结束后 i == 2,三个函数看到的都是 2。
解决:用默认参数在定义时「快照」当前值:
python
callbacks = [lambda i=i: i for i in range(3)]
print([f() for f in callbacks]) # [0, 1, 2]这是「默认参数在函数定义时求值」这一特性的刻意运用(默认参数坑见第 6 章)。工程上更推荐避免在循环里制造裸 lambda,改用偏函数或明确函数。
35.3 *args、**kwargs 与参数传递
*args 收集位置参数为 tuple,**kwargs 收集关键字参数为 dict:
python
def build_request(method, *args, **kwargs):
print(method) # "POST"
print(args) # ("/api/users",)
print(kwargs) # {"timeout": 3, "retries": 2}
build_request("POST", "/api/users", timeout=3, retries=2)拆包(调用侧):* 展开序列,** 展开映射:
python
params = {"timeout": 3, "retries": 2}
build_request("POST", "/api/users", **params)
values = [1, 2, 3]
total(*values) # 等价 total(1, 2, 3)⚠️ 一个关键语义:Python 的「参数传递」既不是值传递也不是引用传递,而是「按对象引用传递」。函数内对参数重新赋值不会影响调用方,但修改可变对象的内容会影响:
python
def append(item, items):
items.append(item) # 修改调用方传入的 list
def reassign(items):
items = [] # 只改了局部名字,调用方不受影响理解这一点能避免大量「为什么 list 传进去被改了」的困惑。
35.4 面向对象进阶:魔术方法、property、super 与 MRO
魔术方法(dunder methods)让自定义类融入 Python 协议:
python
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self): # 调试用的可读表示
return f"Vector({self.x}, {self.y})"
def __eq__(self, other): # 支持 ==
return (self.x, self.y) == (other.x, other.y)
def __add__(self, other): # 支持 +
return Vector(self.x + other.x, self.y + other.y)property 把方法伪装成属性,用于受控访问:
python
class Account:
def __init__(self, balance):
self._balance = balance
@property
def balance(self):
return self._balance
@balance.setter
def balance(self, value):
if value < 0:
raise ValueError("余额不能为负")
self._balance = valuesuper() 用于调用父类方法,配合多继承时按 MRO(Method Resolution Order,方法解析顺序)查找:
python
class B: pass
class C: pass
class D(B, C): pass
print(D.__mro__) # (D, B, C, object)MRO 用 C3 线性化算法确定,super() 严格按 MRO 顺序找下一个实现,不是简单「找父类」。理解 MRO 能解释多继承下 super() 的实际调用路径,避免「明明调了父类却跳到了另一个类」的困惑。
35.5 类变量 vs 实例变量、slots
类变量属于类,所有实例共享;实例变量属于实例:
python
class Config:
default_timeout = 3 # 类变量,所有实例共享
def __init__(self, timeout=None):
self.timeout = timeout or self.default_timeout # 实例变量⚠️ 通过实例给「看起来像类变量」的名字赋值,会创建实例变量,而不是修改类变量:
python
Config.default_timeout = 5 # 修改类变量
c = Config()
c.default_timeout = 10 # 创建实例变量,类变量仍是 5__slots__ 限制实例只能有指定属性,节省内存(不再为每个实例创建 __dict__):
python
class Point:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = y要点:__slots__ 会去掉 __dict__,实例不能动态添加属性;大规模创建小对象(如数据处理中的记录)时能显著省内存,普通业务类不必刻意使用。
35.6 字符串与字节:str、bytes 与编码
Python 3 严格区分「文本」str 和「字节」bytes:
python
text = "中文" # str,Unicode 码点序列
raw = text.encode("utf-8") # bytes,UTF-8 编码后的字节
back = raw.decode("utf-8") # str
print(type(raw)) # <class 'bytes'>
print(raw) # b'\xe4\xb8\xad\xe6\x96\x87'要点:
str是无编码概念的「Unicode 字符串」,bytes才是编码后的字节流。- 读写文件、网络传输都涉及「str ↔ bytes」转换,要显式指定编码,避免依赖平台默认编码。
- Python 3.14 及以前,
open()的默认编码依赖 locale(PEP 686 计划在 Python 3.15 将 UTF-8 设为默认);跨平台代码应显式写encoding="utf-8"。 - 常见错误
UnicodeDecodeError/UnicodeEncodeError基本都源于「用错编码解码/编码」。
AI 工程中处理文档、日志、API 响应时,「文本与字节的边界」是最常见的编码坑来源。
35.7 导入机制与模块缓存
import 会执行模块代码一次,并把模块对象缓存到 sys.modules:
python
import sys
import math_utils
print(math_utils is sys.modules["math_utils"]) # True要点:
- 同一模块在同一进程内只会执行一次顶层代码,后续 import 直接取缓存。
- 这解释了为什么「重复 import 不会重复执行模块级代码」,也解释了「改了文件但不重启进程,import 不会生效」(缓存)。
- 模块级代码(如连接数据库、读配置)会随 import 执行,属于副作用,要注意放置位置。
from module import name会执行整个模块,只是只把name绑定到当前命名空间。
包 vs 模块:包是含 __init__.py 的目录,import package.module 会先执行 package/__init__.py。现代 Python 中 __init__.py 可省略(命名空间包),但显式保留能让结构更清晰、避免命名空间包带来的路径歧义。
快速记忆清单
- Python 是 AI 工程生态最重要的语言之一。
- 缩进是语法,不是格式偏好。
- list、dict、set、tuple 是基础中的基础。
- 虚拟环境必须掌握,避免依赖污染。
- 类型标注不会改变运行时,但能提升工程质量。
- FastAPI + Pydantic 是 AI 服务常见组合。
- LangChain/LangGraph 学习离不开 Python 工程基础。
- 前端 AI 全栈不一定训练模型,但必须会把模型能力做成稳定产品。