Python精讲 - 大二学生系统性学习指南
📚 本文档专为大二学生设计,帮您系统性学习 Python 🎯 学习目标:掌握 Python 核心语法与常用工程实践,能独立完成中小型项目 ⏱️ 建议学习时间:6-8周,每周10-15小时(先期学过本系列《MySQL精讲》效果更佳)
🧑💻 版本说明: 本文档以最新版 Python(个人学习:3.14)为准编写。 文中出现 🧑💻 个人学习(最新版) 与 🏭 企业生产(3.12 / 3.11 / 存量3.10 / 3.9) 标识处, 表示该语法或行为在企业常见版本中的使用差异,请根据实际环境选择写法。
目录
第一部分:基础入门
第1章 Python简介与环境搭建
1.1 什么是Python?
Python 是一种解释型、面向对象、动态类型的高级编程语言,由荷兰程序员 Guido van Rossum 于 1991 年首次发布。它以简单、易读、生态庞大著称。
为什么 Python 如此流行?
- ✅ 语法简洁,接近自然语言,学习曲线平缓
- ✅ 跨平台:Windows / Linux / macOS 一行代码全兼容
- ✅ 胶水语言:能轻松调用 C/C++/Java/Rust 写的库
- ✅ 生态巨大:AI、Web、数据分析、自动化、爬虫全部有成熟库
- ✅ 社区活跃,招聘需求量大(AI 时代更甚)
典型应用领域:
- 人工智能 / 机器学习:TensorFlow、PyTorch、scikit-learn
- 数据分析与可视化:pandas、NumPy、Matplotlib
- Web 开发:Django、Flask、FastAPI
- 运维自动化:Ansible、可编写运维脚本
- 爬虫:requests、Scrapy、BeautifulSoup
- 科学计算:SciPy、SymPy
🏭 企业现实: 国内互联网公司大量后端服务用 Java/Go,但数据、AI、自动化脚本几乎全靠 Python;传统行业(银行、财务、制造业)常用 Python 做报表处理、数据清洗和办公自动化——本系列第15章就是财务主题项目,非常贴合实际。
Python vs MySQL(本系列两部曲):
| 对比 | Python | MySQL |
|---|---|---|
| 定位 | 通用编程语言 | 关系型数据库 |
| 你写的 | 逻辑与功能 | 数据存取与查询 |
| 典型配合 | 用 Python 读写 MySQL 数据 | 存储数据供 Python 查询 |
1.2 Python 版本:谁是"最新",谁是"企业主流"?(重点,面试爱问)
Python 每一年发布一个大版本(3.x),没有 LTS/Innovation 之分,但有明确的维护阶段:
| 阶段 | 含义 | 例子 |
|---|---|---|
| feature(功能版) | 新特性只在此阶段加入 | 3.14(2025-10 发布,现已到 3.14.7) |
| bugfix(缺陷修复) | 修复 bug,不再加新特性 | 3.13(3.13.15) |
| security(安全维护) | 只修安全问题 | 3.12、3.11、3.10 |
| end-of-life(EOL) | 不再维护,官方停止一切更新 | 3.9(2025-10 已 EOL) |
当前版本格局(2026-09 时点):
- 🧑💻 个人学习(绝对最新):Python 3.14(当前 3.14.7;3.15 已进入预发布,预计 2026-10-01 首发)
- 🏭 企业主流(安全维护期):3.12 / 3.11(EOL 分别 2028-10 / 2027-10,许多公司 2026 年前后正从 3.8/3.9 迁移到 3.11/3.12)
- 🏭 企业存量(危险区):3.10(2026-10 即将 EOL)、3.9(已 EOL)、偶见 3.8(已 EOL 多年)
🧑💻 个人学习(最新版):直接安装 3.14,本文所有语法均可运行。 🏭 企业生产差异:见各章 🏭 提示块与文末《附录 E 版本兼容速查表》;遇到诡异报错先看
Python xxx.x(python --version)确认版本,很多"语法错误"其实是企业还在较老版本。
版本速查口诀:
- "3.6 引入 f-string","3.8 引入海象运算符","3.9 必看:内置泛型 list[str]"
- "3.10 是大分水岭"——模式匹配
match/case、联合类型X | Y都是 3.10+,存量 3.9 项目升级时最爱踩 - "3.11 性能与并发"——TaskGroup、tomllib、ExceptionGroup
- "3.12+ 新时代"——清理旧模块(distutils/imp 下线)、f-string 规则放宽;3.14 默认启用延迟求值注解
1.3 Python安装配置与环境
Windows安装(推荐)
- 打开官网 https://www.python.org/downloads/ 下载最新 3.14.x
- 运行安装包,务必勾选 "Add python.exe to PATH"(否则命令行找不到 python)
- 验证:cmd
python --version python -c "print('Hello')" - Windows 还自带
py启动器,可在多版本间切换:cmdpy -3 --version # 用 3.x 最新版 py -3.13 --version # 指定小版本
Linux安装(Ubuntu/Debian为例)
# 1. 系统自带 3.12(Ubuntu 24.04)或 3.11/3.10
python3 --version
# 2. 若要装官方最新版,用 deadsnakes PPA
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.14 python3.14-venv python3.14-pip
python3.14 --version⚠️ PEP 668(企业必知): 新版各 Linux 发行版都声明"系统 Python 为外部管理环境",直接
pip install ...装到系统会报error: externally-managed-environment。这正是为了防止污染系统 Python。 🧑💻 个人做法:凡是装第三方库,一律先进虚拟环境(见 1.3),浏览器(系统级工具如 pipx 也可)。 🏭 企业做法:虚拟环境 / Docker 镜像 / conda 环境是标配,线上绝不pip装系统 Python。
macOS安装
# 方案一:Homebrew
brew install python@3.14
python3 --version
# 方案二:官网 pkg 安装包(自带 tkinter)虚拟环境 venv(重中之重,一定养成习惯)
虚拟环境 = 独立于系统的 Python 副本,每个项目一套依赖,互不污染。
# 创建(Windows 与 Linux/macOS 命令略有差异)
python -m venv .venv # 在项目目录下创建名为 .venv 的环境
# 激活
# Windows (CMD): .venv\Scripts\activate
# Windows (PowerShell): .venv\Scripts\Activate.ps1
# Linux / macOS: source .venv/bin/activate
# 激活后命令行前缀出现 (.venv),此时安装的库都进这个环境
pip install requests
# 导出 / 重建依赖(部署共享)
pip freeze > requirements.txt
pip install -r requirements.txt
# 退出
deactivate🏭 企业提示:
requirements.txt或pyproject.toml是团队协作的标准依赖管理方式;新项目多直接用 uv(一款超快的 Python 包管理工具)替代 pip,用法uv venv/uv add requests。
环境变量与启动器差异
| 命令 | 常见环境 | 说明 |
|---|---|---|
python | Windows | 通常指向最新版 3.x |
python3 | Linux/macOS | 指向系统 Python3 |
py | Windows | 官方启动器,多版本切换 |
1.4 Python开发工具
- IDLE:Python 自带的极简 IDE,零安装,适合前两周
- VS Code(强烈推荐):装 Python 扩展,轻量好用
- PyCharm:JetBrains 出品,功能全面(Community 版免费)
- Jupyter Notebook:交互式笔记本,数据分析/AI 首选
# VS Code 已装 Python 扩展后:
# 新建 .py 文件 → F5 运行;Shift+Enter 可在 Python 交互环境逐行运行选中代码1.5 第一个Python程序与输入输出
# hello.py
print("你好,Python!") # 输出并换行
print("Python", "3.14", sep="-", end="!\n") # 分隔符与结尾控制
name = input("请输入你的名字:") # 输入永远是字符串
print(f"欢迎,{name}!")交互式 REPL(Read-Eval-Print-Loop): 在终端敲 python(或 py)进入,逐行执行、立即看到结果,是学习新语法最快的工具。
>>> 1 + 1
2
>>> type(3.14)
<class 'float'>
>>> exit()📌
input()返回的永远是字符串,要参与数学运算必须先转换:pythonage = int(input("年龄:")) # 转 int;输入非数字会抛 ValueError(见第8章)
1.6 本章练习
- 练习1:安装 Python 3.14,确认
python --version输出版本 - 练习2:创建并激活一个虚拟环境
.venv,尝试pip freeze看是否为空 - 练习3:写一段程序:
input()读姓名与出生年份,打印"XX 今年大约 XX 岁" - 练习4:在 REPL 里分别输入
3 / 2、3 // 2、3 ** 2,记录结果差异(下一章将详解)
第2章 变量、运算符与数据类型
2.1 变量与命名
Python 变量无需声明类型,赋值即创建,类型随值而定。
name = "Alice" # str
age = 20 # int
score = 88.5 # float
is_student = True # bool命名规范(PEP 8):
- 标识符由字母、数字、下划线组成,不能以数字开头
- 变量/函数用小写下划线(
student_name);常量全大写(MAX_COUNT) - 不能用关键字:
if、for、class、def、import等
# 正确
student_name = "Tom"
max_retry = 3
# 错误示范(注释掉避免干扰运行)
# 1name = "x"
# class = "x"同时给多个变量赋值:
a = b = c = 0 # 链式赋值
x, y = 1, 2 # 元组解包
x, y = y, x # 交换变量(经典一行)2.2 数据类型概览
| 类型 | 说明 | 例子 | 是否可变 |
|---|---|---|---|
int | 整数(任意精度) | 42 | 否 |
float | 浮点数 | 3.14 | 否 |
complex | 复数 | 1+2j | 否 |
bool | 布尔值 | True / False | 否 |
str | 字符串 | "hi" | 否 |
bytes | 字节串 | b"hi" | 否 |
list | 列表 | [1, 2] | 是 |
tuple | 元组 | (1, 2) | 否 |
dict | 字典 | {"a": 1} | 是 |
set | 集合 | {1, 2} | 是 |
frozenset | 不可变集合 | frozenset({1}) | 否 |
🏭 企业版本差异(类型注解写法,面试高频):
- 🧑💻 最新版(3.9+):内置类型可以直接当泛型注解——
def sq(x: list[int]) -> int。- 🏭 3.9 之前:必须写
List[int](大写的typing.List);3.7/3.8 项目里仍处处可见List[int]/Dict[str, int],看到别惊讶。
查看类型与判断类型:
type(3.14) # <class 'float'>
isinstance(3, int) # True;isinstance 支持继承判断
isinstance("a", (str, bytes)) # 元组里任一匹配即为 True2.3 运算符
算术运算符:
| 运算符 | 含义 | 例子 |
|---|---|---|
+ - * / | 加减乘除 | 7 / 2 → 3.5 |
// | 整除(向下取整) | 7 // 2 → 3;-7 // 2 → -4 |
% | 取余 | 7 % 2 → 1 |
** | 幂 | 2 ** 10 → 1024 |
+= 等 | 复合赋值 | a += 1 等价 a = a + 1 |
比较与逻辑运算符:
== != > < >= <= # 比较
and or not # 逻辑(返回操作数值,不只是 True/False)身份与成员:
a is None # 身份比较(判断是否为 None,推荐而非 ==)
2 in [1, 2, 3] # True,成员判断
"py" in "python" # True海象运算符 :=(3.8+ 新增,可用但别滥用):
# 传统写法:先算再判断
data = input()
if data:
print(data)
# 海象写法:赋值与判断一步完成,少写一行
if (data := input()):
print(data)
# 典型场景:while 循环里读行
while (line := file.readline()):
print(line.strip())🏭 版本提示:
:=、位置/关键字限定参数(见 5.2)都是 3.8+。3.7 及更早不支持,若企业还在 3.7(极少了),看到:=需改写。
整型除法大坑(面试): 3.x 中 7 / 2 是浮点 3.5(2.x 时代是整数 3,这就是"3.0 大版本"的最知名变更之一)。
2.4 类型转换
int("42") # 42,字符串转整数
float("3.14") # 3.14
str(42) # "42"
bool("") # False;空容器/0/None 都为 False
bool("a") # True;非空即 True
int(3.9) # 3(截断,不四舍五入)
round(3.14159, 2) # 3.14
# 进制转换
int("ff", 16) # 255
hex(255) # '0xff'
bin(10) # '0b1010'布尔转换规则(重要): 以下值在条件判断中视为 False:False、0、0.0、""、[]、()、{}、set()、None。其余一切为 True。
2.5 字符串基础
三种写法与转义:
s1 = '单引号'
s2 = "双引号"
s3 = """多行
字符串""" # 三引号可换行,常用于长文本/文档
s4 = "换行\n制表\t反斜杠\\ 引号\""
s5 = r"raw\path\n不转义" # 原始字符串,正则/路径常用常用方法(字符串不可变,方法都返回新串):
"hello".upper() # 'HELLO'
" hi ".strip() # 'hi'(去空白)
"a,b,c".split(",") # ['a', 'b', 'c']
"-".join(["a","b"]) # 'a-b'
"hello".replace("l","L") # 'heLLo'
"abc".startswith("a") # True
"abc".find("b") # 1;找不到返回 -1
"3.14".isnumeric() # False;"123".isdigit() → True
len("中文") # 2 —— len 返回字符数字符串切片(同样适用于列表/元组):
s = "python"
s[0] # 'p'
s[-1] # 'n'
s[0:3] # 'pyt'(含头不含尾)
s[:2] # 'py'
s[::-1] # 'nohtyp'(反转)f-string(3.6+,最推荐的格式化方式):
name, score = "Tom", 88.5
print(f"{name} 考了 {score} 分") # 简单插入
print(f"{name:10s} | {score:6.1f}") # 对齐与小数位控制
print(f"{score:.2%}") # 百分比
print(f"3 * 4 = {3*4}") # 内部可放表达式
print(f"{score=}") # 输出 score=88.5,调试神器
print(f"{{{score}}}") # 输出 {88.5}(双大括号转义)🏭 版本差异(f-string 的限制放宽,3.12+ 才可用):
- 3.12+(个人最新版与主流企业版):f-string 内允许嵌套使用同种引号、允许反斜杠,如
f"{d['key']}"、f"{x:>{width}}"- 3.11 及更早:上面两行会
SyntaxError,只能绕行f"{d['key']}"(异种引号)——企业存量 3.10/3.9 项目尤其注意- 3.14 进一步改进:
=调试的输出更精美,且内嵌等号表达式可用
2.6 本章练习
- 练习1:写程序读入
radius,打印圆面积πr²(import math用math.pi),保留 2 位小数 - 练习2:用切片把字符串
"Python"输出为"pyht"、"noth"、倒序 - 练习3:解释为什么
0.1 + 0.2 == 0.3是False(浮点二进制表示,用round处理) - 练习4:用 f-string 打印两列对齐的成绩单(姓名左对齐10字符、分数右对齐6字符两位小数)
第3章 流程控制
3.1 条件判断 if / elif / else
score = 75
if score >= 90:
grade = "A"
elif score >= 60:
grade = "B"
else:
grade = "C"
print(grade)要点:
- 用缩进(惯例 4 空格)表示代码块,不要混用 Tab
- 条件非
True/False时会按"布尔转换规则"判断(见 2.4) - 三目表达式:
value = "成年" if age >= 18 else "未成年"
# 链式比较(Python 特色)
if 60 <= score < 90:
print("及格")
# 语义化判断优于裸布尔(代码可读性)
if not user: # 避免 if user is not True 这类写法
print("用户不存在")3.2 循环 while 与 for
# while 循环
n = 0
while n < 5:
print(n, end=" ")
n += 1
print()
# for 遍历可迭代对象(列表/字符串/range/字典键…)
for i in range(1, 6): # range(开始, 结束不包含, 步长)
print(i, end=" ")
print()
for ch in "abc":
print(ch, end="")
print()
# 带索引遍历(enumerate)
names = ["Tom", "Jerry"]
for idx, name in enumerate(names, start=1):
print(idx, name)
# break / continue / else(循环未被 break 打断则执行 else)
for i in range(10):
if i == 3:
continue # 跳过本次,i=3 不输出
if i == 8:
break # 提前终止,i=8 不输出
print(i, end=" ")
else:
print("正常结束")📌 Python 特有的
for...else:循环**自然结束(没有 break)**才进入 else 块,常用来写"找不到就如何"的逻辑。
3.3 模式匹配 match / case(3.10+ 新增)
match 是 3.10 引入的结构化模式匹配,比一串 if/elif 更清晰,是 3.10+ 面试常客。
command = "list"
match command:
case "quit":
print("再见")
case "list" | "ls": # 多值用 | 合并
print("列出内容")
case _: # _ 通配兜底(相当于 else)
print("未知命令")
# 解包匹配:按结构匹配
point = (1, 2)
match point:
case (0, 0):
print("原点")
case (x, 0):
print(f"在 X 轴上,x={x}")
case (x, y):
print(f"普通点 ({x}, {y})")
# 带条件的守卫 guard
age = 20
match age:
case n if n >= 18:
print("成年")
case _:
print("未成年")🏭 版本差异(1/4 重要):
- 3.10+(个人最新版/3.12/3.11):
match可用。- 3.9 及更早(企业存量):
match是SyntaxError,只能改写if/elif。企业项目从 3.9 升到 3.10+ 时,很多团队会主动用 match 重写繁琐 if/else。
3.4 异常处理基础
异常在 Python 里无处不在,先给个"能用",第8章再系统详讲。
try:
num = int(input("数字:"))
print(100 / num)
except ZeroDivisionError:
print("不能除以0")
except ValueError:
print("必须是整数")
finally:
print("无论成败都会执行") # 常用于关文件/资源3.5 本章练习
- 练习1:打印 1~100 中 3 的倍数与 5 的倍数(能被15整除的打"FizzBuzz")
- 练习2:输入一个正整数 n,用 while 计算
1^2+2^2+...+n^2 - 练习3:用
for...else判断某数是否为素数 - 练习4(3.10+):用
match解析一个(动词, 名词)元组命令,至少支持("go", "north")/("take", "key")/ 其他;先在 3.14 上跑通,再用 if 改写对比
第4章 数据结构(核心容器)
4.1 列表 list
列表是可变、有序的容器,几乎是最常用的数据结构。
nums = [1, 2, 3, 4]
nums.append(5) # 末尾添加 [1,2,3,4,5]
nums.insert(0, 0) # 指定位置插入 [0,1,2,3,4,5]
nums.remove(3) # 删除值 3(第一个匹配)
x = nums.pop() # 弹出并返回末尾;pop(0) 弹开头
nums.extend([6, 7]) # 批量添加
nums[0] = 100 # 按下标修改
nums[1:3] = [20, 30] # 切片批量替换
len(nums); nums.count(1); 1 in nums; nums.index(2)
nums.sort() # 原地排序;sorted(nums) 返回新列表
nums.reverse()
# 切片返回新列表
sub = nums[1:4]
copy = nums[:] # 浅拷贝列表推导式(必会):
squares = [x * x for x in range(10)] # [0,1,4,...,81]
evens = [x for x in range(20) if x % 2 == 0] # 带条件
pairs = [(x, y) for x in range(3) for y in range(2)] # 双重循环🏭 企业提示: 列表推导式比等价 for+"append" 更 Pythonic,代码审查中常见互改。但注意不要为了炫技写超复杂推导,可读性优先。
4.2 元组 tuple 与解包
元组不可变,安全、可哈希(可作 dict 键)。
t = (1, 2, 3)
a, b, c = t # 解包
first, *rest = t # 星号收集 rest=[2,3]
t2 = 1, 2 # 不加括号也是元组
single = (5,) # 单元素元组必须有逗号!
CONFIG = ("127.0.0.1", 3306) # 常量配置常用元组
# 交换变量的本质就是元组解包
x, y = y, x📌 函数返回多个值,本质是返回一个元组:
def f(): return 1, 2。
4.3 字典 dict
字典是键值对容器,3.7+ 起保证插入顺序。
student = {"name": "Tom", "age": 20, "class_id": 1}
student["age"] = 21 # 改
student["grade"] = "A" # 增(键不存在即为新增)
del student["grade"] # 删
score = student.get("score", 0) # 安全取值,不存在返回默认值
# 遍历三种姿势
for key in student: # 遍历键
print(key)
for k, v in student.items(): # 最常用
print(k, v)
for v in student.values(): # 值
print(v)
# 合并与更新
a = {"x": 1}
b = {"y": 2}
merged = a | b # 3.9+ 用 | 合并
a |= b # 相当于 a.update(b)
a.update({"z": 3})
# 字典推导式
squares_map = {x: x * x for x in range(5)}🏭 版本差异(3 处):
- 键顺序保证:3.7+ 官方保证有序(3.6 是 CPython 实现细节)。3.6 及更早顺序无保证。
dict | dict合并运算符:3.9+。- 浅拷贝/默认值工厂:
dict.fromkeys(["a","b"], 0);需要"缺失即生成"用collections.defaultdict(见 9.4)。
4.4 集合 set / frozenset
集合无序、去重,成员判断 O(1),支持数学运算。
s = {1, 2, 3}
s.add(4); s.discard(99) # remove 不存在会报错,discard 不会
s = set([3, 4, 5])
a = {1, 2, 3}
b = {3, 4, 5}
a | b # 并 {1,2,3,4,5}
a & b # 交 {3}
a - b # 差 {1,2}
a ^ b # 对称差 {1,2,4,5}
a <= b # 子集判断
# 去重经典
unique = list(set([1, 1, 2, 3, 3])) # [1,2,3](顺序不保证)⚠️ 集合元素必须可哈希:数字/字符串/元组可以;列表/字典不行(可变)。
4.5 常用内建函数
len() sorted() min() max() sum()
enumerate() zip() list() tuple() dict() set()
reversed() range() any() all() abs() round()# zip:并行遍历
names = ["Tom", "Jerry"]
scores = [88, 92]
for n, s in zip(names, scores):
print(n, s)
pairs = dict(zip(names, scores)) # {'Tom': 88, 'Jerry': 92}
# any / all
any([False, True]) # True
all([1, 2, 3]) # True
# sorted 的 key 参数(重要)
students = [("Tom", 88), ("Jerry", 92)]
students.sort(key=lambda s: s[1], reverse=True) # 按键排序4.6 本章练习
- 练习1:用推导式生成 1~50 所有偶数组成列表,再求其和
- 练习2:统计一句话里每个字符出现次数(先用 dict 手写,再尝试
collections.Counter) - 练习3:两个列表
["a","b","c"]与[1,2]用 zip 转字典,观察结果 - 练习4:集合运算:求两个班级学生(姓名列表)的并集、交集、只在A班的学生
第二部分:核心技能
第5章 函数与作用域
5.1 函数定义与调用
def greet(name):
"""返回问候语(docstring,文档字符串)"""
return f"你好,{name}!"
def say_hi():
print("Hi") # 无 return,返回 None
def add(a, b):
return a + b
print(greet("Tom")) # 你好,Tom!要点:
def 函数名(参数):+ 缩进函数体- 没有
return或return不带值,返回None - 函数对象本身就是"一等公民",可作为参数传递/赋值(第10章装饰器基石)
5.2 参数机制(必会,面试高频)
# 1. 位置参数(按顺序)
def f(a, b, c): ...
f(1, 2, 3)
# 2. 关键字参数(按名字,顺序可乱)
f(c=3, a=1, b=2)
# 3. 默认值参数(放在最后;默认值只计算一次)
def g(x, base=2): ...
g(4) # base=2
g(4, 10) # base=10
# 4. 可变参数 *args(打包成元组)
def total(*nums):
return sum(nums)
total(1, 2, 3)
# 5. 关键字参数 **kwargs(打包成字典)
def show(**kw):
for k, v in kw.items():
print(k, v)
show(name="Tom", age=20)
# 6. 解包调用(序列/字典展开传参)
args = (1, 2)
add(*args) # add(1, 2)
kw = {"a": 1, "b": 2}
add(**kw) # add(a=1, b=2)
# 7. 位置/关键字限定符(3.8+)
def h(a, b, /, c, *, d):
...
h(1, 2, 3, d=4) # ✓ a,b 必须位置;d 必须关键字
# h(1, 2, c=3, d=4) 也合法
# h(a=1, b=2, 3, d=4) ❌ a,b 不能关键字传参🏭 版本提示:
/与*限定符都是 3.8+。3.7 及更早不支持(企业已几乎无 3.7)。
默认值可变对象大坑(面试必考):
def append_item(item, lst=[]): # ❌ 默认值在定义时创建一次
lst.append(item)
return lst
append_item(1) # [1]
append_item(2) # [1, 2] —— 竟然"记住了"!共享了同一列表
# 正确写法:默认用 None,函数内再创建
def append_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst5.3 返回值与会话
def analyze(nums):
return sum(nums), max(nums), len(nums) # 返回元组
s, m, n = analyze([1, 5, 3]) # (9, 5, 3)
# return None 的写法约定
def log(level="INFO", msg=""):
if not msg:
return # 提前退出,返回 None
print(f"[{level}] {msg}")5.4 变量作用域与 global / nonlocal
x = 10 # 全局作用域
def demo():
x = 1 # 局部变量,遮蔽外层(不改全局)
print(x) # 1
demo()
print(x) # 10(没被改)
def change():
global x # 声明修改全局变量 x
x = 100
change()
print(x) # 100
def outer():
n = 1
def inner():
nonlocal n # 声明修改外层函数的局部变量
n += 1
inner()
print(n) # 2📌 LEGB 查找顺序:Local(局部)→ Enclosing(外层函数)→ Global(模块级)→ Built-in(内建)。日常 90% 只用到局部与全局两层。
5.5 匿名函数 lambda
lambda 参数: 表达式——只能写一个表达式,不能有语句。
f = lambda x: x * 2
f(4) # 8
# 常用场景:sorted / max / min 的 key
words = ["banana", "fig", "apple"]
sorted(words, key=lambda w: len(w)) # 按长度排序
students = [{"name": "A", "score": 88}, {"name": "B", "score": 92}]
best = max(students, key=lambda s: s["score"])💡 逻辑复杂就不要写 lambda,用普通
def+ 具名函数更可读(PEP 8 建议)。
5.6 函数式工具
nums = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x * x, nums)) # [1,4,9,16,25]
odds = list(filter(lambda x: x % 2, nums)) # [1,3,5]
# 结合 reduce(functools)
from functools import reduce
total = reduce(lambda a, b: a + b, nums) # 15
# 但多数场景推导式/内建更 Pythonic
squares = [x * x for x in nums]5.7 本章练习
- 练习1:写
is_prime(n)判断素数,再用它找出 2~100 的素数 - 练习2:写
def describe(**info)接收可变关键字参数并格式化输出成多行文本 - 练习3:修复可变默认值坑:写函数
add_to_log(msg, log=None)且 log 可为已有列表 - 练习4:用
lambda+sorted对("Tom",22)、("Jerry",18)、("Ann",25)按年龄排序
第6章 面向对象编程
6.1 类与对象
class Student:
school = "示例大学" # 类变量(所有实例共享)
def __init__(self, name, age): # 构造方法:创建对象时自动调用
self.name = name # 实例变量(每个对象自己的)
self.age = age
def intro(self): # 实例方法,第一个参数是 self
return f"{self.name},{self.age}岁,来自{Student.school}"
s1 = Student("Tom", 20)
s1.age = 21 # 修改实例属性
print(s1.intro())核心概念:
__init__初始化实例;self指代"当前对象",命名约定俗成- 类变量 vs 实例变量:类变量共享,实例变量独立
6.2 属性私有约定与 property
Python 没有真正私有,用下划线表达"约定":
class Account:
def __init__(self, owner, balance):
self._owner = owner # 单下划线:约定"不要外部直接访问"
self.__balance = 0 # 双下划线:名字改写(name mangling),类外 access 会报错
self.deposit(balance)
def deposit(self, amount):
if amount <= 0:
raise ValueError("金额必须为正")
self.__balance += amount
@property # 把方法变成"只读属性"(外部 account.balance)
def balance(self):
return self.__balance
acct = Account("Tom", 100)
acct.deposit(50)
print(acct.balance) # 150(像属性一样读,背后是方法)
# acct.balance = 999 # ❌ 无 setter,禁止直接改6.3 继承与多态
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError
class Dog(Animal):
def speak(self):
return f"{self.name} 汪汪"
class Cat(Animal):
def speak(self):
return f"{self.name} 喵喵"
animals = [Dog("旺财"), Cat("咪咪")]
for a in animals:
print(a.speak()) # 多态:同一方法,不同表现
# super() 调用父类方法
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
class Graduate(Student):
def __init__(self, name, age, mentor):
super().__init__(name, age) # 复用父类初始化
self.mentor = mentor
# 判断
isinstance(Dog("x"), Animal) # True
Cat.__mro__ # 方法解析顺序🏭 企业提示: Python 支持多继承,但现实项目(尤其 Django 等框架)更常用组合与协议(Protocol, 见12.2);能不用多继承就不用,可读性与维护成本是关键。
6.4 魔术方法(双下划线方法)
class Money:
def __init__(self, yuan):
self.yuan = yuan
def __repr__(self): # 调试/REPL 显示
return f"Money({self.yuan})"
def __str__(self): # print/str 显示
return f"¥{self.yuan}"
def __add__(self, other): # 支持 +
return Money(self.yuan + other.yuan)
def __eq__(self, other): # 支持 ==
return self.yuan == other.yuan
def __lt__(self, other): # 支持 < 和排序
return self.yuan < other.yuan
m1 = Money(100); m2 = Money(50)
print(m1 + m2) # ¥150
print(m1 == Money(100)) # True
print(sorted([Money(5), Money(2), Money(9)])) # 按金额排序常用魔术方法速查: __init__ __str__ __repr__ __eq__ __lt__ __len__ __getitem__ __iter__ __enter__/__exit__(with 支持)、__call__。
6.5 dataclass(3.7+,企业最爱)
@dataclass 自动生成 __init__/__repr__/__eq__,少写大量样板代码。
from dataclasses import dataclass, field
@dataclass
class Product:
sku: str
price: float
tags: list = field(default_factory=list) # 可变默认值必须用 factory
p1 = Product("A001", 9.9, ["新品"])
p2 = Product("A001", 9.9)
print(p1) # Product(sku='A001', price=9.9, tags=['新品'])
print(p1 == p2) # False(tags 不同)🏭 版本差异:
- 🧑💻 3.10+:
@dataclass(slots=True)可用(以__slots__节省内存,见 14.3)。- 🏭 3.10 之前:
slots=True参数不存在,会TypeError;3.7-3.9 只能写普通 dataclass。
6.6 类方法、静态方法与实例方法
class Config:
debug = False
@classmethod
def from_dict(cls, data): # 传 cls,可访问类属性/用于替代构造器
obj = cls()
obj.debug = data.get("debug", False)
return obj
@staticmethod
def validate_port(port): # 不依赖实例与类,纯工具方法
return 0 < port < 65536
def show(self): # 实例方法
print("debug =", self.debug)
c = Config()
c.show() # debug = False
c2 = Config.from_dict({"debug": True})
print(Config.validate_port(8080)) # True6.7 本章练习
- 练习1:定义
BankAccount,用@property防护负数余额,deposit/withdraw接口与校验 - 练习2:定义
Rectangle与Circle继承Shape(都有area()),多态打印各自面积 - 练习3:用
__lt__支持按(price, name)排序的Product类 - 练习4:用
@dataclass定义 3 字段的Transaction(amount, category, date)并打印
第7章 文件操作与路径处理
7.1 文本文件读写
# 写入
with open("note.txt", "w", encoding="utf-8") as f:
f.write("第一行\n")
f.write("第二行\n")
# 追加:模式改为 "a"
# 读
with open("note.txt", "r", encoding="utf-8") as f:
content = f.read() # 一次读全部
lines = f.readlines() # 按行读成列表
# 或逐行
for line in f: # 文件对象本身就是可迭代的(推荐,省内存)
print(line.strip())模式速查:
| 模式 | 含义 |
|---|---|
"r" | 只读(默认),不存在报 FileNotFoundError |
"w" | 只写,清空原有内容,不存在则创建 |
"a" | 追加,不清空 |
"x" | 独占创建,文件已存在会报错 |
"rb" / "wb" | 二进制模式 |
📌 务必用
with:自动关闭文件,异常时也保证关闭;忘记关闭文件会丢失缓冲数据/占文件句柄。
编码是中文项目的第一大坑:
# 故意用错编码写,再读就乱码
with open("note.txt", "w", encoding="gbk") as f:
f.write("你好")
# 读取时指定 utf-8 → UnicodeDecodeError
# 统一约定:全项目所有文件开/写都用 encoding="utf-8"7.2 二进制文件
with open("img.dat", "wb") as f:
f.write(bytes([0xFF, 0x00, 0x10]))
with open("img.dat", "rb") as f:
data = f.read()
print(data.hex()) # 'ff0010'7.3 CSV 与 JSON(项目一/二的核心)
JSON(标准库,最常用):
import json
data = {"name": "Tom", "scores": [88, 92], "active": True}
with open("student.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2) # 中文不转义 + 美观缩进
with open("student.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["scores"][0]) # 88CSV(用标准库 csv,别自己 split(",")——会被引号/逗号坑):
import csv
rows = [
{"date": "2026-09-01", "amount": -15.5, "cat": "餐饮"},
{"date": "2026-09-02", "amount": 5000, "cat": "工资"},
]
with open("trans.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["date", "amount", "cat"])
writer.writeheader()
writer.writerows(rows)
with open("trans.csv", "r", encoding="utf-8") as f:
for row in csv.DictReader(f):
print(row["amount"], row["cat"])💡
newline=""是为了正确处理跨平台的换行;写 CSV 忘加它,Excel 打开会多空行。
7.4 pathlib 路径处理(推荐替代 os.path)
from pathlib import Path
p = Path("data") / "report.csv" # 跨平台路径拼接(不再手写反斜杠)
p.name # 'report.csv'
p.suffix # '.csv'
p.parent # PosixPath('data')
p.exists() # False
p.mkdir(parents=True, exist_ok=True) # 创建目录
p.write_text("hi", encoding="utf-8") # 一行写文本
text = p.read_text(encoding="utf-8") # 一行读文本
# 遍历目录:删除 data 下所有 .tmp 文件
for f in Path("data").glob("*.tmp"):
f.unlink()
# 当前脚本所在目录(写相对资源路径的关键)
BASE = Path(__file__).resolve().parent7.5 内存文件 io.StringIO
from io import StringIO
buf = StringIO()
buf.write("第1行\n")
buf.write("第2行\n")
print(buf.getvalue()) # 当作文件操作字符串,无需真文件7.6 本章练习
- 练习1:把成绩单(字典列表)写入 CSV,再用 csv 读回打印
- 练习2:逐行读 10 万行的文本文件,统计行数与总字数(体会
for line in f省内存) - 练习3:用 pathlib 在项目下建
logs/2026/目录并写入app.log - 练习4:JSON 嵌套读写:存
{"user": {...}, "accounts": [...]}再还原
第8章 异常处理与调试
8.1 异常体系
Python 异常是等级制的类结构,捕获父类会连带捕获所有子类。
BaseException
├── Exception ← 99% 的业务异常都挂在它下面
│ ├── ArithmeticError
│ │ ├── ZeroDivisionError
│ ├── LookupError
│ │ ├── IndexError, KeyError
│ ├── ValueError
│ ├── TypeError
│ ├── FileNotFoundError
│ ├── OSError
│ └── ...
└── SystemExit, KeyboardInterrupt ← 不要轻易捕获int("abc") # ValueError
[1][5] # IndexError
{}["k"] # KeyError
1 + "1" # TypeError
open("缺.txt") # FileNotFoundError
open("a.txt", "x") # FileExistsError
10 / 0 # ZeroDivisionError8.2 try / except / else / finally
try:
n = int(input("请输入除数:"))
r = 100 / n
except (ValueError, ZeroDivisionError) as e: # 多个异常一个分支
print(f"输入不合法:{e}")
except Exception as e: # 兜底(但别滥用)
print(f"未知错误:{e}")
else:
print(f"结果是 {r}") # 无异常才执行(常用于只在该成功时运行的代码)
finally:
print("收尾必然执行") # 释放资源⚠️ 捕获
Exception兜底要克制:它会把 bug 也吞掉,难以排查。原则是能精确就精确。
8.3 自定义异常与异常链
class InsufficientBalanceError(Exception):
"""余额不足异常(继承 Exception 即成为可抛业务异常)"""
def withdraw(balance, amount):
if amount > balance:
raise InsufficientBalanceError(f"余额{b:.2f}不足,需{amount:.2f}")
return balance - amount
# raise from 保留"根因"(异常链),排查时能看到原始错误
try:
json.loads(not_json_text)
except json.JSONDecodeError as e:
raise ValueError("配置格式错误") from e8.4 ExceptionGroup 与 except*(3.11+)
可以一次抛出一组异常,用 except* 分组处理(多任务并发场景很实用)。
def validate(items):
errs = []
for i, item in enumerate(items):
if item < 0:
errs.append(ValueError(f"{i} 号不能为负数"))
if errs:
raise ExceptionGroup("校验失败", errs)
try:
validate([1, -2, -3, 4])
except* ValueError as eg:
print("发现负数项:", eg.exceptions)🏭 版本提示: ExceptionGroup/
except*为 3.11+。3.10 及更早的存量项目不支持,需自行遍历收集;建议团队换代后用try-except*重写批量断言。个人 3.14/3.12/3.11 环境直接可用。
8.5 断言、logging 与调试
# 断言:开发期的前置条件检查
def set_age(age):
assert isinstance(age, int) and 0 < age < 150, "年龄非法"
...
# logging:比 print 更适合留日志(分级、可关闭、可进文件)
import logging
logging.basicConfig(level=logging.INFO)
logging.debug("调试信息") # 不显示(level 默认 WARNING 之上才显)
logging.info("流程正常")
logging.warning("磁盘将满")
logging.error("操作失败")
# pdb:简单的断点调试
# 在代码里写 breakpoint() 运行到此处即进入 pdb
# n=下一步, p 表达式=打印, c=继续, q=退出🏭 企业提示: 生产环境用
logging打点,配日志采集(ELK 等)做监控;
8.6 本章练习
- 练习1:写
safe_divide(a, b),除零返回None而非抛异常 - 练习2:自定义
OutOfStockError,在"库存扣减"函数中 raise 并附带当前库存 - 练习3(3.11+):用 ExceptionGroup 校验一批
Transaction金额与日期合法性 - 练习4:给第6章的
BankAccount.withdraw加上raise from的错误链与测试
第三部分:高级特性
第9章 模块、包与标准库精选
9.1 模块 import 机制
每个 .py 文件都是一个模块;import 时执行该模块并得到命名空间。
# math_demo.py
import math
print(math.sqrt(16)) # 4.0
from math import pi, sqrt # 直接导入名字
print(pi)
import math as m # 别名(短名)
print(m.floor(3.7)) # 3
# 自定义模块:同目录建 utils.py,在别的文件里 import utilsif __name__ == "__main__":(企业必写):
# utils.py
def double(x):
return x * 2
if __name__ == "__main__":
# 只有"直接运行 python utils.py"才执行;被别人 import 时不执行
print(double(21))💡 这一步让模块既可当库导入、又可当脚本运行,是 Python 工程的通用惯例。
import 搜索顺序: 内建模块 → sys.path 中的路径(脚本目录、环境变量 PYTHONPATH、site-packages)。
import sys
sys.path # 查看当前搜索路径9.2 包(Package)
包 = 一个带 __init__.py 的目录(3.3+ 其实可省略该文件,但保留更规范)。
项目/
├── app/
│ ├── __init__.py
│ ├── models.py
│ └── services/
│ ├── __init__.py
│ └── billing.py
└── main.py# main.py
from app.models import User
from app.services.billing import Invoice
# 相对导入(包内文件之间)
# from .models import User 当前包内向上
# from ..services import ... 上一级9.3 第三方库与 pip / venv / uv
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install requests pandas # 装包
pip list # 查看已装
pip show requests # 查看详情
pip uninstall requests
pip freeze > requirements.txt # 生成依赖清单(部署/交接必备)🏭 PEP 668(Linux 系统 Python 直装报错)重申:
error: externally-managed-environment时不要--break-system-packages强行装;正确姿势是 venv。 🧑💻 uv(可选升级):uv venv、uv add requests、uv run main.py,速度数倍于 pip,新项目可直接上手。
常用第三方库地图(先知道,用到再学):
| 库 | 用途 | 备注 |
|---|---|---|
| requests | HTTP 请求 | 网络一章详讲 |
| Flask / FastAPI / Django | Web 后端 | FastAPI 自带 OpenAPI 文档 |
| pandas / NumPy | 数据分析 | 企业报表神器 |
| Matplotlib | 绘图 | 配合 pandas |
| BeautifulSoup / Scrapy | 爬虫 | |
| pytest | 测试 | 12.5 详讲 |
9.4 标准库精选(打字都要会的)
import math, random, statistics
math.pi, math.sqrt(9), math.pow(2, 10), math.floor(3.7)
random.random() # [0,1) 随机浮点
random.randint(1, 6) # 1~6 随机整数(含两端)
random.choice(["A", "B"]) # 随机选一
random.shuffle(list_of_items) # 洗牌
statistics.mean([1, 2, 3]) # 2from collections import Counter, defaultdict, deque, namedtuple
Counter("abracadabra") # {'a': 5, 'b': 2, ...} 计数神器
Counter(words).most_common(3) # 出现最多的 3 个
dd = defaultdict(list) # 缺失键自动初始化
dd["a"].append(1) # 不用先判断键在不在
# 等价手写:d.get(k, []).append(1) 之类
dq = deque([1, 2, 3]) # 双端队列,两端 O(1)
dq.appendleft(0); dq.pop()
Point = namedtuple("Point", ["x", "y"]) # 轻量"小类"
p = Point(1, 2); p.x # 1from itertools import product, permutations, count, islice
from functools import lru_cache, cache, partial, reduce
list(product([0, 1], repeat=3)) # 8 个 (0/1) 三元组
list(permutations("ABC", 2)) # 排列
islice(count(10, 5), 3) # 10,15,20 惰性无限流
# cache(3.9+)与 lru_cache:记忆化,递归加速
from functools import cache
@cache
def fib(n):
return n if n < 2 else fib(n-1) + fib(n-2)
print(fib(60)) # 秒算,没有缓存会慢到天荒地老
add_5 = partial(lambda x, y: x + y, 5) # 预填参数 → add_5(3)=8🏭 版本提示:
functools.cache(无参数版)与上表多数是 3.9+;3.8 及更早只有lru_cache(maxsize=128)。
from datetime import datetime, date, timedelta, timezone
now = datetime.now() # 本地时间
today = date.today()
d = date(2026, 9, 11)
d2 = d + timedelta(days=30) # 加减日期
now.strftime("%Y-%m-%d %H:%M:%S") # 格式化 '2026-09-11 09:30:00'
datetime.strptime("2026-01-01", "%Y-%m-%d") # 解析字符串
now.timestamp() # 转 UNIX 时间戳
from datetime import UTC # 3.11+ 才有 UTC 常量
now.astimezone(UTC)🏭 版本提示:
datetime.UTC(3.11+);3.9/3.10 需写timezone.utc(更老兼容写法)。
# zoneinfo:带 IANA 时区(3.9+)
from zoneinfo import ZoneInfo
beijing = datetime(2026, 6, 1, 12, tzinfo=ZoneInfo("Asia/Shanghai"))
print(beijing.astimezone(ZoneInfo("UTC")))
# ⚠️ Windows 需 pip install tzdata 才有时区数据库(Linux/macOS 自带)# tomllib:解析 TOML 配置(3.11+;3.9/3.10 需第三方 toml/tomli)
import tomllib
with open("pyproject.toml", "rb") as f:
cfg = tomllib.load(f)🏭 版本提示:
tomllib(3.11+),读取pyproject.toml(新项目统一用它替代 setup.py)。3.10 及更早企业项目用tomli(或老toml)。
9.5 本章练习
- 练习1:建
stats_utils.py模块(含mean/median/mode_simple),写main.py导入调用 - 练习2:用
Counter统计段落词频,输出 Top3 与其词数 - 练习3:用
datetime写"距期末考试还有多少天/小时" - 练习4:用
.venv安装requests并pip freeze生成 requirements.txt
第10章 迭代器、生成器与装饰器
10.1 迭代协议
可迭代对象(iterable):可被 for 遍历(如 list/str/dict/range)。iter() 得到迭代器(iterator),next() 取下一个。
it = iter([1, 2, 3])
next(it) # 1
next(it) # 2
next(it) # 3
# next(it) # StopIteration 异常(正常耗尽信号)# 判断"是否可迭代"
from collections.abc import Iterable
isinstance("abc", Iterable) # True
isinstance(42, Iterable) # False10.2 生成器(yield,省内存之魂)
生成器函数:含 yield,调用它不立即执行,返回一个惰性求值的迭代器。
def count_up(n):
i = 1
while i <= n:
yield i # 每次 next() 暂停此处,返回 i
i += 1
for x in count_up(5):
print(x, end=" ")
# 生成器表达式(用()不是[])
gen = (x * x for x in range(10))
sum(gen) # 285,一次性消费
# 内存对比:前 100 万个数
# nums = [i for i in range(1_000_000)] ❌ 整列表占内存
# gen = (i for i in range(1_000_000)) ✅ 惰性,O(1)💡 何时用生成器:处理大文件逐行、数据流、无限序列、只需"逐个用"的场景。第7章
for line in f就是文件对象内部在用迭代协议。
10.3 yield from 与管道
def flatten(nested):
for sub in nested:
yield from sub # 把子迭代器"展开"(平铺)
print(list(flatten([[1, 2], [3, 4]]))) # [1, 2, 3, 4]
# 管道:多个生成器串联(一次处理一步)
def read_logs(path):
with open(path, encoding="utf-8") as f:
yield from f
def only_error(lines):
for line in lines:
if "ERROR" in line:
yield line10.4 装饰器原理(函数作为对象 + 闭包)
def timer(func):
import time
def wrapper(*args, **kwargs):
t0 = time.perf_counter()
result = func(*args, **kwargs)
print(f"{func.__name__} 耗时 {(time.perf_counter()-t0)*1000:.1f}ms")
return result
return wrapper
@timer
def slow_sum(n):
return sum(range(n))
slow_sum(1_000_000) # 输出耗时并返回结果过程拆解: @timer 等价于 slow_sum = timer(slow_sum)。装饰器接收"原函数",返回"包装函数",实现不改原函数代码就给行为加料。闭包 = 内层函数引用外层变量(如 func),外层返回后仍可用。
# 带参数的装饰器(再加一层)
def repeat(times):
def deco(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return deco
@repeat(3)
def hello():
print("Hi")10.5 装饰器三件套 @wraps / @cache / @property
# 不保留原函数元信息,调试易迷失 → 用 functools.wraps
import functools, time
def timer(func):
@functools.wraps(func) # 让 wrapper 伪装成 func(__name__/__doc__)
def wrapper(*args, **kwargs):
...
return func(*args, **kwargs)
return wrapper
@timer
def hello(): "print hi"
print(hello.__name__) # 'hello'(无 wraps 会是 'wrapper')# 记忆化缓存(9.4 见过)
from functools import cache
@cache
def expensive(x):
# 模拟耗时计算
return x * x# property(6.2 用过):把一个方法当属性,本质也是装饰器
class Celsius:
def __init__(self, t): self._t = t
@property
def fahrenheit(self): return self._t * 9 / 5 + 3210.6 本章练习
- 练习1:改第4章练习:用生成器惰性产生 1~1000000 的平方和
- 练习2:写装饰器
@logged:打印函数名、参数、返回值,供第15章记账项目打审计日志 - 练习3:
yield from展平两层嵌套列表[[1,2],[3,[4,5]]](思考多层怎么办,提示递归) - 练习4:对比
for x in range(...)与手写iter/next两种遍历方式,画出生成器执行过程中状态暂停的示意
第11章 并发编程基础
11.1 并发模型选择(先想清楚用哪个)
| 模型 | 适用场景 | 特点 |
|---|---|---|
| 多线程 threading | 大量 I/O(网络、文件、数据库) | GIL 使 CPU 密集无加速 |
| 多进程 multiprocessing | CPU 密集(运算、图像、爬虫抓取) | 绕开 GIL,进程间通信较重 |
| 协程 asyncio | 高并发 I/O(数千连接) | 单线程协作式切换,开销最小 |
🏭 企业现实: 高并发 Web 服务更多直接用框架(FastAPI/Django 皆基于 asyncio(FastAPI)或 WSGI 线程池);你写的 Python 脚本做爬虫/批量接口调用时,多线程或 asyncio 最常见。
GIL(必考面试点): CPython 的全局解释器锁使同一进程同一时刻只能有一个线程执行字节码。后果:多线程对 CPU 密集任务几乎无加速,但对 I/O 密集非常有效(I/O 等待时释放锁让给别的线程)。
11.2 threading(I/O 密集)
import threading, time
def worker(name, sec):
time.sleep(sec)
print(f"{name} 完成,耗时 {sec}s")
t1 = threading.Thread(target=worker, args=("A", 2))
t2 = threading.Thread(target=worker, args=("B", 1))
t1.start(); t2.start()
t1.join(); t2.join() # 等待两个线程结束
print("主线程结束")
# I/O 等待并行:总耗时约 2s 而非 3s被多个线程修改同一变量→竞态:
import threading
counter = 0
lock = threading.Lock()
def inc():
global counter
for _ in range(1_000_000):
with lock: # 拿锁保护临界区
counter += 1
threading.Thread(target=inc).start()
threading.Thread(target=inc).start()
print(counter) # 不加锁可能 < 2000000(竞态)💡 企业里"多线程共享变量"普遍用队列
queue.Queue(生产者-消费者),天然线程安全,比裸变量+锁好写得多。
11.3 multiprocessing(CPU 密集)
from multiprocessing import Pool
def heavy(x):
return x * x
if __name__ == "__main__": # 多进程下必须写,Windows 尤其
with Pool(4) as pool: # 4 个进程并行
print(pool.map(heavy, range(10)))11.4 asyncio 协程(async/await)
import asyncio
async def fetch(i):
await asyncio.sleep(0.3) # 模拟 I/O 等待(协程让出控制权)
return f"结果{i}"
async def main():
tasks = [asyncio.create_task(fetch(i)) for i in range(5)]
results = await asyncio.gather(*tasks) # 并发等待
print(results)
asyncio.run(main()) # 总耗时 ≈0.3s 而非 1.5sTaskGroup(3.11+,更规范的并发任务组织):
async def main():
async with asyncio.TaskGroup() as tg: # 3.11+:自动等待/统一异常管理
tg.create_task(fetch(1))
tg.create_task(fetch(2))
asyncio.run(main())🏭 版本提示:
asyncio.TaskGroup / asyncio.timeout是 3.11+;3.9/3.10 只能用asyncio.gather等旧写法。
11.5 线程/进程池 Executor
from concurrent.futures import ThreadPoolExecutor
def download(url):
return f"{url} 下载完成"
with ThreadPoolExecutor(max_workers=8) as pool:
results = pool.map(download, [f"url{i}" for i in range(20)])
for r in results:
print(r)
# 还有 ProcessPoolExecutor(CPU 密集用)11.6 本章练习
- 练习1:用 10 个线程并发请求 30 个测试接口场景(本地用
time.sleep模拟),对比串行时间 - 练习2:用
queue.Queue实现"日志生产者-消费者",主线程发消息、后台线程写文件 - 练习3:
time.sleepvsasyncio.sleep:分别用多线程与协程跑 5 个 1s 任务对比总耗时 - 练习4(3.11+):TaskGroup 并发抓 5 个 URL,其中一个抛异常观察整体行为
第12章 类型注解与代码质量
12.1 类型注解基础
注解不影响运行(除非你装了运行时检查),值在于:可读性、IDE 提示、静态检查(mypy/ruff)。
def greet(name: str, times: int = 1) -> str:
return name * times
def total(nums: list[float]) -> float: # 3.9+ 内置泛型
return sum(nums)
age: int = 20
scores: list[int] = [88, 92]
user: dict[str, str] = {"name": "Tom"}
# 返回 None
def log(msg: str) -> None: ...🏭 版本差异:
- 🧑💻 3.9+:内置泛型
list[int]/dict[str, int]直接用。- 🏭 3.8 及更早:必须
from typing import List, Dict写List[int]。企业 3.10/3.9 存量若还没升级,扔大量List[int],升级到 3.9+ 后可逐步清理。- 可变参数注解:
*args: int、**kwargs: str。
12.2 typing 模块精选
from typing import Optional, Union, Any, Protocol, TypeAlias, Self
x: Optional[int] = None # 等价 int | None(见下)
y: Union[int, str] = 1 # 3.10+ 可直接写 int | str
data: Any = anything # 关闭类型检查(尽量少用)
# TypeAlias:给复杂类型起名(3.10+)
UserID: TypeAlias = int
def find(u: UserID): ...
# Protocol:结构化类型("鸭子类型"静态版,企业契约设计常用)
from typing import Protocol
class Sizable(Protocol):
def __len__(self) -> int: ...
def count_all(*objs: Sizable) -> int:
return sum(len(o) for o in objs)
count_all("abc", [1, 2]) # 5,无需继承任何东西
# Self(3.11+):标注"返回自身类型"的链式方法
class Builder:
def set_name(self, name: str) -> Self:
self.name = name
return self🏭 版本提示:
X | Y联合写法、ParamSpec/Concatenate/TypeAlias为 3.10+;Self、TypeVarTuple为 3.11+。3.9 存量需Optional/Union老写法。
12.3 延迟求值注解与运行时检查
3.14 重磅变化(面试/迁移话题):
- 🧑💻 3.14+:注解默认延迟求值(PEP 649)——
def f(x: 未定义的东西)也能通过,字符串里引用"未来才会导入的类型"不再报错,启动更快。 - 🏭 3.7~3.13:注解默认立即求值;想在旧版本提前享受,要在文件顶部写
from __future__ import annotations(团队项目常加这一行统一行为)。
from __future__ import annotations # 3.7+ 可用:把注解变成字符串延迟处理
# TypeGuard(3.10+):让静态检查器明白"if 判断后的窄化"
from typing import TypeGuard
def is_list_of_int(x) -> TypeGuard[list[int]]:
return isinstance(x, list) and all(isinstance(i, int) for i in x)
nums = [1, 2]
if is_list_of_int(nums):
print(nums[0] + 10) # 类型检查器这里认为它就是 list[int]12.4 PEP 8 与代码质量
核心规范(速记):
- 缩进 4 空格;行宽约 79~88 字符(超长建议折行)
import置顶,标准库→第三方→本地模块分组,各留空行- 变量/函数
lower_snake_case;类CapWords;常量UPPER_SNAKE_CASE == None写成is None;== True/False写成if x:/if not x:- 命名一目了然,少用
tmp/a/b
# 工具链(企业标配,先知道)
# pip install ruff mypy pytest
ruff check . # 代码风格+常见 bug 检查
ruff format . # 自动格式化
mypy .
python -m pytest -v # 运行测试12.5 单元测试入门
unittest(标准库):
# test_money.py
import unittest
from money import Money
class TestMoney(unittest.TestCase):
def test_add(self):
self.assertEqual(Money(100) + Money(50), Money(150))
def test_eq(self):
self.assertEqual(Money(5), Money(5))
if __name__ == "__main__":
unittest.main()
# 运行:python -m unittest test_money -vpytest(企业主流,更简洁):
# 同一断言,pytest 风格
from money import Money
def test_add():
assert Money(100) + Money(50) == Money(150)
def test_lt():
assert Money(3) < Money(9)python -m pytest -v # 自动发现 test_*.py
python -m pytest -k add # 只跑名字含 add 的12.6 本章练习
- 练习1:给第6章
BankAccount补齐类型注解,并用 mypy 检查 - 练习2:用 pytest 给
safe_divide、withdraw各写 3 个用例(正常/边界/异常) - 练习3:定义
Protocol描述"可统计金额的对象",让Account与Coupon都满足它 - 练习4:跑
ruff check格式化本章代码,指出被规范化的 3 处
第四部分:实战应用
第13章 网络与Web基础
13.1 HTTP 请求:urllib 与 requests
# 用标准库 urllib 发 GET
from urllib.request import urlopen
import json
with urlopen("https://httpbin.org/json") as resp:
data = json.load(resp)
print(data["slideshow"]["title"])# 企业主流:requests(更友好)
import requests
r = requests.get("https://httpbin.org/get", params={"a": 1}, timeout=5)
r = requests.post("https://httpbin.org/post",
json={"name": "Tom"}, timeout=5)
print(r.status_code, r.headers["content-type"])
r.json() # 自动解析 JSON
r.text # 原始文本
r.raise_for_status() # 非 2xx 抛异常(务必调用)🏭 企业提示: 依赖接口要设
timeout、处理重试与降级;公司内部接口常用requests.Session()复用连接。生产级客户端再进阶再看httpx(支持异步)。
13.2 内置 http.server(零依赖起服务)
# 一句话起静态文件服务
# python -m http.server 8000 → http://localhost:8000 查看当前目录
# 自定义处理器(简单 API 演示)
from http.server import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.end_headers()
self.wfile.write("Hello".encode("utf-8"))
HTTPServer(("0.0.0.0", 8888), Handler).serve_forever()💡 仅适合学习/内网 demo;对外生产必须用 FSGI/WSGI 服务器或框架。
13.3 Flask 快速入门(第三方首选入门)
pip install flask# app.py
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.get("/")
def home():
return "Hello Flask"
@app.get("/api/hello")
def hello():
name = request.args.get("name", "world")
return jsonify({"msg": f"Hello, {name}"})flask --app app run --debug # 默认 http://127.0.0.1:5000企业框架决策(面试/选型):
| 框架 | 定位 | 适合 |
|---|---|---|
| Flask | 轻量、灵活 | 小型服务、新手入门、内部工具 |
| FastAPI | 异步、自动文档(Swagger)、类型友好 | 新 API 服务、AI 服务 |
| Django | 全家桶(ORM/Admin/认证) | 中大型业务系统 |
🏭 企业现实: 银行/财务类系统见到 Django(自带后台管理与权限)很多;新一代接口多 FastAPI。第15章项目三会演示 Flask 与"复利计算器接口"的结合。
13.4 环境变量与配置管理
import os
API_KEY = os.environ.get("API_KEY") # 01env 配置,别硬编码进代码
DEBUG = os.environ.get("DEBUG", "0") == "1"
DB_URL = os.environ.get("DB_URL", "sqlite:///app.db")
# 本地开发常配合 .env 文件(python-dotenv)
# pip install python-dotenv
from dotenv import load_dotenv
load_dotenv() # 读取项目根 .env🔒 安全铁律: 密钥(API Key/数据库密码)绝不写入代码或提交 git;用环境变量/密钥管理服务(企业:Vault/KMS/云 Secret Manager)。
13.5 本章练习
- 练习1:requests 请求
https://httpbin.org/get,打印状态码并raise_for_status - 练习2:Flask 写
/api/currency?amount=100&from=USD&to=CNY(汇率写死本地表)并测试 - 练习3:把课堂项目的关键参数全部改为环境变量读取,并写
.env示例 - 练习4:用内置 http.server 起静态站点 + 自定义路由返回 JSON
第14章 性能与最佳实践
14.1 性能剖析
# timeit:微观计时
import timeit
print(timeit.timeit("'-'.join(str(n) for n in range(100))", number=10000))
# cProfile:宏观剖析找热点(先找到性能瓶颈再优化,别过早优化)
# python -m cProfile -s cumulative 脚本.py14.2 常见优化套路(面试常聊)
# 1. 用生成器取代整列表(超大集合)
squares = (x * x for x in range(10_000_000)) # ✓ 惰性
# 2. 字符串拼接用 join 而非 +=(大量循环时尤其重要)
parts = ["a"] * 1000
s = "".join(parts) # ✓
# s += ... 在循环里每次都要新建字符串 ❌
# 3. 集合/字典做成员判断(O(1))取代列表 in (O(n))
allowed = {"accept", "reject"}
if status in allowed: ...
# 4. 查找用字典而非 if/elif 链(分支多时)
def handle(cmd):
handlers = {"start": do_start, "stop": do_stop}.get(cmd)
if handlers:
handlers()
# 5. 局部变量优先于全局(属性访问开销小技巧)
# 循环里反复用 len(...) 存入局部变量14.3 内存与资源管理
# __slots__:给类"抽屉柜",省内存(大量实例时显著)
class Money:
__slots__ = ("amount", "currency") # 只允许这两个属性,禁动态加属性
def __init__(self, amount, currency):
self.amount = amount
self.currency = currency
# with 管理资源(文件/锁/连接)
with open("f.txt") as f: ...
with lock: ...
# 惰性加载(用到才算)
_config_cache = None
def get_config():
global _config_cache
if _config_cache is None:
_config_cache = load_json("config.json")
return _config_cache🧑💻 3.13 / 3.14 实验特性(了解一下即可):
- free-threading(无 GIL 构建):3.13 起可选
--disable-gil构建,真正多线程并行,但目前第三方库兼容性需要逐一验证,生产谨慎。- JIT:3.13 起内置实验性即时编译器(3.11 已先大幅提升解释器性能 ~10-60%);日常代码无需关注,运行更快是白赚的。 🏭 企业提示: 服务器一般用发行版/官方二进制,默认带 GIL 的标准构建,别在生产擅自改。
14.4 部署与打包
# 1. 环境固化
python -m venv .venv
pip freeze > requirements.txt # 或新项目用 uv lock
# 2. 入口收敛
# main.py 内含 if __name__ == "__main__": 结构作为唯一入口
# 3. 打包成单文件可执行(分发给不会装环境的人)
pip install pyinstaller
pyinstaller --onefile main.py # dist/main(Linux)或 exe(Windows)
# 注意:加 --add-data 引入资源、--hidden-import 补齐动态导入
# 4. 容器部署(企业标配)示意
# Dockerfile
# FROM python:3.14-slim
# COPY . /app && WORKDIR /app
# RUN pip install -r requirements.txt
# CMD ["python", "main.py"]🏭 企业等级: 生产环境不要跑"裸 python main.py",要配 systemd / Docker / K8s;改造遵循12 因素原则(配置环境变量化、日志到 stdout、无状态等)。
14.5 本章练习
- 练习1:用 timeit 对比
join与循环+=拼接 10 万字符串的时间 - 练习2:给
Money加__slots__,用sys.getsizeof对比 1 万个实例的内存 - 练习3:cProfile 剖析第10章
fib(无缓存)找出热点 - 练习4:把第15章项目一的记账程序用 pyinstaller 打成单文件(可选)
第15章 综合项目案例(财务专题)
🎯 本章三个项目主题全部围绕"个人/家庭财务",由浅入深,把前 14 章的知识串起来,并逐步引入真正的工程实践。建议边看边敲、敲完重构。
15.1 项目一:家庭记账本(CLI版)
目标: 记收入/支出 → 存 JSON → 按类别/月份汇总报表。知识点:dataclass、函数、文件/JSON、datetime、基础测试。
# ledger.py
import json
from dataclasses import dataclass, field
from datetime import date
from pathlib import Path
DATA_FILE = Path("ledger.json")
@dataclass
class Transaction:
amount: float # 收入为正、支出为负
category: str
note: str = ""
date: str = field(default_factory=lambda: date.today().isoformat())
@property
def is_income(self) -> bool:
return self.amount > 0
def load() -> list[Transaction]:
if not DATA_FILE.exists():
return []
with DATA_FILE.open("r", encoding="utf-8") as f:
return [Transaction(**t) for t in json.load(f)]
def save(items: list[Transaction]) -> None:
with DATA_FILE.open("w", encoding="utf-8") as f:
json.dump([t.__dict__ for t in items], f,
ensure_ascii=False, indent=2)
def add(items: list[Transaction]) -> None:
amount = float(input("金额(收入为正、支出为负):"))
category = input("类别(餐饮/交通/工资/其他):").strip()
trans = Transaction(amount, category)
items.append(trans)
save(items)
print("已记账")
def report(items: list[Transaction]) -> None:
if not items:
print("暂无记录")
return
total = sum(t.amount for t in items)
income = sum(t.amount for t in items if t.is_income)
expense = income - total
print(f"收入: {income:.2f} 支出: {abs(expense):.2f} 结余: {total:.2f}")
from collections import defaultdict
by_cat = defaultdict(float)
for t in items:
by_cat[t.category] += t.amount
print("按类别:")
for cat, amt in sorted(by_cat.items(), key=lambda kv: kv[1]):
print(f" {cat}: {amt:+8.2f}")
def main() -> None:
items = load()
while True:
cmd = input("(a)记账 (r)报表 (q)退出:").strip().lower()
if cmd == "a":
add(items)
elif cmd == "r":
report(items)
elif cmd == "q":
break
if __name__ == "__main__":
main()练习与扩展:
- 加
--date/--month过滤;按month生成月度报表文件 - 写 pytest:
add后load回读一致、金额为 0 拒绝 - 用
@logged装饰器(第10章练习2)给 save 暂审计日志
15.2 项目二:银行流水分析工具(CSV + 统计)
目标: 导入银行导出的 CSV → 计算指标 → 分类汇总 → 可选图表。知识点:csv/pathlib、statistics/math、groupby、第三方依赖边界。
# bank_analysis.py
import csv, math
from collections import defaultdict
from pathlib import Path
# 假设银行导出格式:date,description,amount(amount 负为支出)
def load_transactions(path: Path) -> list[dict]:
with path.open("r", encoding="utf-8-sig") as f: # utf-8-sig 去掉 BOM
return list(csv.DictReader(f))
def analyze(rows: list[dict]):
amounts = [float(r["amount"]) for r in rows]
income = [a for a in amounts if a > 0]
expense = [a for a in amounts if a <= 0]
print(f"笔数: {len(rows)}")
print(f"总收入: {sum(income):.2f}")
print(f"总支出: {abs(sum(expense)):.2f}")
print(f"支出均值: {abs(sum(expense)/len(expense)):.2f}" if expense else "")
print(f"单笔最大支出: {abs(min(expense)):.2f}" if expense else "")
print(f"标准差(度量波动): {statistics.stdev(amounts):.2f}" if len(amounts) > 1 else "")
def by_category(rows: list[dict]):
agg = defaultdict(float)
for r in rows:
agg[r.get("category", "其他")] += float(r["amount"])
for cat, amt in sorted(agg.items(), key=lambda kv: kv[1]):
print(f" {cat}: {amt:+10.2f}")
if __name__ == "__main__":
import statistics
rows = load_transactions(Path("statement.csv"))
analyze(rows)
print("按类别:")
by_category(rows)可选:可视化(第三方,标注差异)
# pip install matplotlib
import matplotlib
matplotlib.use("Agg") # 无界面导出图片
import matplotlib.pyplot as plt
def plot(rows: list[dict], out: Path):
data = sorted(((r.get("category", "其他"), abs(float(r["amount"])))
for r in rows), key=lambda kv: kv[1])
cats, amts = zip(*data)
plt.pie(amts, labels=cats, autopct="%.1f%%")
plt.savefig(out)🏭 企业提示: 数据可视化在企业里更常用 pandas + Matplotlib/Seaborn,或直接接 BI 工具(FineReport/Tableau)。你已学的
csv+statistics足够完成纯文本版报表,漂亮图表属于扩展加分。 🧑💻 版本提示: 装 matplotlib 时如果系统 Python 报了 PEP 668,记得先进虚拟环境(1.3)。
练习与扩展:
- 支持
--month 2026-09过滤;统计"本月最大支出类别" - 用
Counter找出现最频繁的交易描述(比如消费商家 Top3) - 引入
dataclass Transaction统一两个项目的数据结构
15.3 项目三:复利与投资规划工具(CLI + Flask 接口化)
目标: 算复利、倒推目标需要的本金/月份,先做 CLI,再用 Flask 暴露成 API。知识点:math、iterative/h函数、Flask、JSON 回程、pytest。
# invest.py
def compound_balance(principal: float, rate: float, months: int) -> float:
"""复利:F = P(1 + r)^n,r 为月利率"""
return principal * (1 + rate) ** months
def plan_months(principal: float, rate: float, target: float) -> int:
"""需多少个月达到 target"""
if principal >= target:
return 0
if principal <= 0:
raise ValueError("本金必须为正")
import math
return math.ceil(math.log(target / principal) / math.log(1 + rate))
# 单元测试(pytest)
# def test_compound():
# assert round(compound_balance(1000, 0.01, 12), 2) == round(1000 * 1.01**12, 2)
# def test_plan():
# assert plan_months(1000, 0.01, 1268) == 24 # ≈ 1000*1.01^24 ≈ 1269.7# app.py —— 把上面的函数暴露成接口
from flask import Flask, jsonify, request
from invest import compound_balance, plan_months
app = Flask(__name__)
@app.get("/api/compound")
def compound_api():
p = float(request.args.get("p", 0))
r = float(request.args.get("r", 0)) / 100 # 年化转月
n = int(request.args.get("n", 1))
return jsonify({"months": n, "balance": compound_balance(p, r / 12 * 12 / 12, n)})🙈 上面 API 简化写了个演示式换算,正式代码应先定义
monthly_rate(annual_pct)、annual_years(months)等清晰函数(避免魔数),这是企业 code review 重点。
练习与扩展:
- 加"每月定投"版公式
F = A·[(1+r)^n - 1]/r并配用例 - 用 Flask 做
/api/plan?p=&r=&target=返回需要月数 - 给 invest.py 写 6 个 pytest 用例(含 0 利率、负数校验边界)
第16章 学习路径与资源推荐
16.1 学习路径建议
第1~4周 → 第1~8章:语法 + 数据结构 + OOP + 文件/异常
(每章练习必须敲完,配套 15 分钟小自测)
第5~6周 → 第9~12章:标准库 + 生成器装饰器 + 并发 + 注解测试
开始写第15章 项目一(记账本)
第7~8周 → 第13~14章 + 项目二、三
最后一周刷 16.3 面试题 + 写一篇学习笔记
建议并行 → 结合《MySQL精讲》:用 Python 连接 MySQL 做"学生成绩管理系统"进阶方向(毕业前按兴趣选一条深耕):
| 方向 | 下一步书目/项目 |
|---|---|
| 数据分析 | pandas/NumPy/Matplotlib → 学习「数据清洗实战」 |
| 后端 | Flask 后学 FastAPI + 数据库 → 部署小服务 |
| AI/机器学习 | scikit-learn → 入门一个 kaggle 比赛 |
| 自动化/爬虫 | requests + BeautifulSoup + 定时任务(scrapyd/cron) |
16.2 推荐学习资源
- 官方教程(必看):https://docs.python.org/zh-cn/3/tutorial/
- 菜鸟教程:快速查语法
- 廖雪峰 Python 教程:中文入门经典(注意其版本较老,淘汰 2.x 内容)
- 练习平台:LeetCode(简单题热身)、牛客网 Python 题库
- 社区:Stack Overflow、Python 官方文档、"Python 每周邮件"
16.3 面试常见问题(速览)
list与tuple的区别?为何tuple可作 dict 键?- 可变默认参数为什么是坑?如何规避?
- GIL 是什么?多线程爬虫为什么依然能提速?
- 深拷贝
copy.deepcopy与=赋值的区别? range返回的是什么?range(10)是列表吗?@staticmethod与@classmethod区别?is与==的区别?None判断用哪个?- 装饰器/生成器各写一个例子(口头)
requests中timeout不设会有什么后果?- 多版本/多环境隔离的方案有哪些?(venv / uv / conda / Docker)
16.4 实战项目建议(衔接MySQL系列)
- 全栈项目一:学生成绩管理系统 —— Python(Flask)+ MySQL:建库(对照《MySQL精讲》第4章)→ 连接 → CRUD → 登录 + 成绩报表导出 CSV
- 全栈项目二:个人记账 Web 版 —— 把项目一 CLI 记账本数据改存 MySQL,加 Flask 页面与汇总图
- 自动化脚本:每周自动拉银行 CSV 跑项目二分析发邮件/写云笔记
16.5 学习建议
- 多敲多跑:每段代码都自己打一遍、改参数看报错,看懂了不等于会了
- 善用报错:报错信息是最好老师,从头读到尾再决定搜不搜
- 代码规范从第一天开始:4 空格缩进、命名、type 注解,企业中这些直接进 code review
- 写笔记:把"坑"(如 PEP 668、乱码、可变默认值)记成自己的知识库
- 先精后广:先把标准库与语法吃透,再追求第三方库数量
附录
A. Python常用内置函数与标准库速查
# 内建函数 TOP20
abs() all() any() bin() bool() dict() enumerate()
filter() float() int() isinstance() len() list() map()
max() min() print() range() round() set() sorted()
str() sum() tuple() type() zip()
# 模块速查
import math # pi sqrt pow floor ceil log
import random # random randint choice shuffle sample
import statistics # mean median stdev
import datetime # datetime date timedelta strftime strptime
import json # dump load dumps loads
import csv # DictWriter DictReader writer reader
import re # search match findall sub split compile
# 常用集合
import collections # Counter defaultdict deque namedtuple
import itertools # product permutations combinations cycle groupby islice
import functools # partial lru_cache cache reduce wraps
import pathlib # PathB. PEP 8代码风格要点
| 规则 | 示例 |
|---|---|
| 缩进 4 空格 | 是 |
| 行宽 ≤88 字符 | black/ruff 默认 |
| 变量/函数 | lower_snake_case |
| 类名 | CapWords |
| 常量 | UPPER_SNAKE_CASE |
| 空行分隔 | 函数间空 2 行,类方法间空 1 行 |
| import 顺序 | 标准库 → 第三方 → 本地,各空行 |
| 比较 | is None / if x: 而非 == None / == False |
| 文档 | 模块、类、函数用三引号 docstring |
C. 常用数据结构选择速查
| 场景 | 选择 |
|---|---|
| 有序可变集合 | list |
| 只读配置/多返回值 | tuple(可哈希) |
| 键值映射 | dict(3.7+ 保序) |
| 去重/集合运算/成员判断 | set / frozenset |
| 计数 | collections.Counter |
| 缺失键自动给默认 | collections.defaultdict |
| 双端快速增删 | collections.deque |
| 轻量不可变小对象 | dataclass 或 namedtuple |
| 需要有序+排序键复用 | sortedcontainers(第三方)或 CD |
D. 常用代码模板
# 1) 优雅读写文件
from pathlib import Path
p = Path("data.json")
data = json.loads(p.read_text(encoding="utf-8"))
p.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
# 2) 安全解析 + 校验
def safe_float(s: str) -> float:
try:
return float(s)
except (TypeError, ValueError):
raise ValueError(f"非法数值: {s!r}") from None
# raise ... from None:隐藏原始异常链,给用户干净的报错
# 3) 可复用的 try-except 模式
try:
result = risky_io()
except (FileNotFoundError, PermissionError) as e:
log.error("IO失败: %s", e)
raise
else:
return result
# 4) 装饰器骨架(带 wraps)
import functools
def my_deco(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 前处理
r = func(*args, **kwargs)
# 后处理
return r
return wrapper
# 5) 并发骨架
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=8) as pool:
list(pool.map(fn, jobs))
# 6) 配置即环境变量
import os
P = os.environ.get("PORT", "8000")
# 7) Flask 最小骨架 + JSON 返回
# from flask import Flask, jsonify
# app = Flask(__name__)
# @app.get("/ping")
# def ping(): return jsonify({"ok": True})E. 版本兼容速查表(个人最新版 vs 企业常见版本)
图例:✅ 支持 ❌ 不支持 ⚠️ 有条件/需注意。
| 特性/语法 | 🧑💻 3.14(最新) | 3.12(企业主流,3.11 同) | 3.10(存量) | 3.9(已EOL,存量2) |
|---|---|---|---|---|
| f-string(3.6+) | ✅ | ✅ | ✅ | ✅ |
| f-string 嵌套引号/反斜杠放宽(3.12+) | ✅ | ✅ | ❌ | ❌ |
海象运算符 :=(3.8+) | ✅ | ✅ | ✅ | ✅ |
位置/关键字限定 /、*(3.8+) | ✅ | ✅ | ✅ | ✅ |
| 字典顺序保证(3.7+) | ✅ | ✅ | ✅ | ✅ |
| 字典合并 `dict | dict`(3.9+) | ✅ | ✅ | ✅ |
str.removeprefix/removesuffix(3.9+) | ✅ | ✅ | ✅ | ✅ |
内置泛型 list[int](3.9+) | ✅ | ✅ | ✅ | ✅ |
| dataclass(3.7+) | ✅ | ✅ | ✅ | ✅ |
@dataclass(slots=True)(3.10+) | ✅ | ✅ | ✅ | ❌ |
联合类型 X | Y(3.10+) | ✅ | ✅ | ✅ | ❌(需 Union) |
模式匹配 match/case(3.10+) | ✅ | ✅ | ✅ | ❌ |
TypeAlias / ParamSpec(3.10+) | ✅ | ✅ | ✅ | ❌ |
ZoneInfo(3.9+,Win 需 tzdata) | ✅ | ✅ | ✅ | ✅ |
datetime.UTC 常量(3.11+) | ✅ | ✅ | ❌ | ❌ |
ExceptionGroup / except*(3.11+) | ✅ | ✅ | ❌ | ❌ |
asyncio.TaskGroup(3.11+) | ✅ | ✅ | ❌ | ❌ |
tomllib(3.11+) | ✅ | ✅ | ❌ | ❌ |
Self 类型(3.11+) | ✅ | ✅ | ❌ | ❌ |
functools.cache(3.9+) | ✅ | ✅ | ✅ | ✅ |
移除 distutils/imp/asynchat | ✅(已移除) | ✅(已移除) | ❌ 仍在 | ❌ 仍在 |
移除 crypt/telnetlib/lib2to3(3.13) | ✅(已移除) | ⚠️ 移除中 | ❌ | ❌ |
| 延迟求值注解 PEP 649 默认(3.14+) | ✅ 默认开启 | ❌(需 __future__) | ❌ | ❌ |
| PEP 668 外部管理环境(Linux 发行版) | ⚠️ 依发行版 | ⚠️ 依发行版 | ⚠️ 依发行版 | ⚠️ 依发行版 |
| free-threading(无 GIL)/ JIT | ⚠️ 实验性 | ❌ | ❌ | ❌ |
速查口诀:
- "3.10 是大分水岭":
match、X | Y、slots=True、TypeAlias 都要 3.10+;3.9 存量最痛 - "3.11 交给企业":TaskGroup、ExceptionGroup、tomllib、
Self、datetime.UTC都是 3.11+ - "3.12 + / 3.13 + 是清理与提速":旧模块下线、f-string 放飞、默认延迟注解(3.14)
- 个人最新版切到 3.14 用起来与 3.12/3.11 差别极小,只有"注解默认延迟 + 模块清理"值得注意
更新日志
- v1.0 (2026-09):初版完成——以 Python 3.14 为基准,构建 4 部分 16 章 + 附录 A~E,含 财务专题项目(记账本 / 银行流水分析 / 复利规划工具)与版本兼容速查表
- 后续将根据学习反馈持续更新
祝您学习愉快! 🎓
如有问题或建议,欢迎反馈!
- 本文链接:https://zzhitao.site/posts/2026-09-14-python
- 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 许可协议。

