前面 18 章把「为什么这样设计」讲透了,这一页只做一件事:把写代码时真正会去翻的语法压成表。建议第一次通读建立索引感,之后把它当案头卡片——写的时候不必回忆章节号,先在这里对号入座,再回正文看完整推导。
本附录所有代码片段都在本机 Python 3.14.6 上实际运行过,输出为真实结果。标注了「3.x+」的语法低于该版本会直接报错,其余语法在 3.12 基线上同样可用。
附录 A Python 语法速查表
字面量与数值写法
| 写法 | 含义 | 备注 |
|---|---|---|
42 / -7 | 整数 | 任意精度,没有溢出 |
1_000_000 | 带下划线的整数 | 下划线只是分隔符,不影响数值 |
0xFF / 0o17 / 0b1010 | 十六 / 八 / 二进制 | 分别等于 255 / 15 / 10 |
3.14 / 1.5e3 | 浮点 | 1.5e3 == 1500.0;二进制浮点有精度误差 |
2j / 3+4j | 复数 | 虚部带 j,实部虚部都是浮点 |
True / False / None | 布尔与空值 | 三者都是单例,用 is 比较 |
"a" / 'a' / """a""" | 字符串 | 三种引号等价;三引号可跨行 |
r"a\nb" / b"bytes" | 原始字符串 / 字节串 | 前者反斜杠不转义;后者元素是 0–255 的整数 |
f"{x}" | f-string | 3.6+,见后文格式说明符 |
数值运算里最容易踩的坑:7 // 2 == 3、-7 // 2 == -4(向下取整),7 % 3 == 1、-7 % 3 == 2(余数符号跟随除数),0.1 + 0.2 == 0.30000000000000004(二进制浮点无法精确表示 0.1)。金额等需要精确十进制的场景改用 decimal.Decimal,见 3.1 数值、字符串与 f-string 格式化
。
运算符优先级
从最低到最高排列,同一行内从左到右结合(** 例外,从右到左):
| 优先级 | 运算符 | 说明 |
|---|---|---|
| 最低 | := / lambda | 海象赋值 / 匿名函数 |
| ↓ | if–else | 条件表达式 |
| ↓ | or / and / not x | 逻辑或、与、非,短路求值 |
| ↓ | in / is / < <= > >= != == | 成员、身份与比较,可链式 |
| ↓ | | / ^ / & | 按位或、异或、与 |
| ↓ | << / >> | 移位 |
| ↓ | + / - | 加减 |
| ↓ | * / / / // / % / @ | 乘除、整除、取模、矩阵乘 |
| ↓ | +x / -x / ~x | 一元正负与按位取反 |
| 最高 | ** | 幂,右结合 |
>>> 2 ** 3 ** 2
512 # 右结合,等价于 2 ** (3 ** 2)
>>> -2 ** 2
-4 # 一元负号优先级低于 **
>>> 1 < 2 < 3
True # 链式比较等价于 (1 < 2) and (2 < 3)
四大容器:常用方法与复杂度
列表 list(可变、有序、允许重复):
| 操作 | 复杂度 | 说明 |
|---|---|---|
lst[i] / lst[i] = x | O(1) | 按索引读写 |
lst.append(x) / lst.pop() | 均摊 O(1) | 尾部追加 / 弹出 |
lst.insert(0, x) / lst.pop(0) | O(n) | 头部插入删除要整体挪动 |
x in lst | O(n) | 线性查找 |
lst.sort() | O(n log n) | 原地排序,返回 None |
元组 tuple:与列表同样支持索引与切片,但不可变,因此可作为字典键、可放进集合。
字典 dict(键值映射,3.7+ 保持插入顺序):
| 操作 | 复杂度 | 说明 |
|---|---|---|
d[k] / d[k] = v | 平均 O(1) | 按键读写 |
d.get(k, default) | 平均 O(1) | 键不存在时返回默认值 |
k in d | 平均 O(1) | 判断键是否存在 |
d.setdefault(k, v) | 平均 O(1) | 键存在则取值,否则插入并返回 |
d.items() / d.keys() / d.values() | O(1) | 返回视图,不复制 |
集合 set(无序、元素唯一、要求可哈希):
| 操作 | 复杂度 | 说明 |
|---|---|---|
s.add(x) / x in s | 平均 O(1) | 增删查 |
s | t / s & t / s - t / s ^ t | 平均 O(len) | 并、交、差、对称差 |
关键结论:需要「查某元素在不在」时,先把容器换成 dict 或 set,in 从 O(n) 降到平均 O(1)。各容器的选择与底层实现见 3.2 列表、元组、字典与集合
。
切片规则
切片写作 seq[start:stop:step],三个位置都可省略,stop 不包含:
>>> s = "abcdef"
>>> s[1:4], s[:3], s[3:], s[::2], s[::-1]
('bcd', 'abc', 'def', 'ace', 'fedcba')
>>> nums = [0, 1, 2, 3, 4, 5]
>>> nums[1:5:2]
[1, 3]
>>> nums[::-1]
[5, 4, 3, 2, 1, 0]
| 写法 | 含义 |
|---|---|
seq[:] | 浅拷贝整个序列 |
seq[::-1] | 反转(返回新对象) |
seq[i:j] | 下标 [i, j) 的片段 |
| 负数下标 | 从尾部计数,-1 是最后一个 |
| 越界索引 | 不报错,自动截断到边界(但 seq[i] 单点取值会报 IndexError) |
推导式
四种容器都有对应的推导式,写法一致:表达式 for 变量 in 可迭代对象 [if 条件]。
>>> [i * i for i in range(5)]
[0, 1, 4, 9, 16]
>>> [i for i in range(10) if i % 2 == 0]
[0, 2, 4, 6, 8]
>>> {c: ord(c) for c in "abc"}
{'a': 97, 'b': 98, 'c': 99}
>>> {c for c in "aabbcc"}
{'a', 'b', 'c'}
>>> list(zip([1, 2, 3], "abc"))
[(1, 'a'), (2, 'b'), (3, 'c')]
- 列表推导用
[],字典用{k: v ...},集合用{...},生成器用(...)。 - 生成器表达式是惰性的,不会一次性把结果算出来,适合大序列。
- 嵌套推导可读性差,超过两层建议改成普通循环。详见 4.1 条件、循环与推导式 。
解包与星号
a, *b, c = [1, 2, 3, 4, 5] 后 b == [2, 3, 4];{**{"x": 1}, "z": 3} 得到 {'x': 1, 'z': 3}。
| 场景 | 写法 | 作用 |
|---|---|---|
| 解包序列 | a, b = pair | 按位置赋值 |
| 收集剩余 | first, *rest = seq | rest 恒为列表 |
| 合并字典 | {**d1, **d2} | 后者覆盖同名键 |
| 展开参数 | f(*args, **kwargs) | 序列拆成位置参数、字典拆成关键字参数 |
| 忽略值 | _, x = pair | 下划线是约定俗成的「不要」 |
函数参数四种形态
def f(a, b=2, *args, c, d=4, **kw):
return a, b, args, c, d, kw
>>> f(1, 9, 8, 7, c=3, x=5)
(1, 9, (8, 7), 3, 4, {'x': 5})
| 形态 | 语法 | 说明 |
|---|---|---|
| 位置参数 | def f(a, b) | 调用时必须按顺序给出 |
| 默认参数 | def f(a, b=2) | 有默认值的参数必须排在无默认值之后 |
| 可变位置 | def f(*args) | args 是元组,收集多余位置参数 |
| 可变关键字 | def f(**kw) | kw 是字典,收集多余关键字参数 |
| 仅位置 | def f(a, /, b) | 3.8+,/ 之前的只能按位置传 |
| 仅关键字 | def f(*, c) | * 之后的只能按关键字传 |
顺序固定为:位置 → 默认 → *args → 仅关键字 → **kw。默认参数在函数定义时求值一次,因此绝不要用可变对象当默认值(见附录 D)。
def g(a, /, b, *, c):
return a, b, c
>>> g(1, 2, c=3)
(1, 2, 3)
作用域与 global / nonlocal
Python 按 LEGB 规则查找名字:Local(当前函数)→ Enclosing(外层函数)→ Global(模块)→ Builtin(内置)。
| 关键字 | 作用 | 使用场景 |
|---|---|---|
global x | 声明 x 指向模块级变量 | 函数内要重新赋值模块变量时 |
nonlocal x | 声明 x 指向外层函数的变量 | 闭包内修改外层函数的计数器 |
counter = 0
def inc():
global counter
counter += 1
def outer():
n = 0
def inner():
nonlocal n
n += 1
return n
return inner
>>> inc(); counter
1
>>> h = outer(); h(), h(), h()
(1, 2, 3)
只读取外层变量不需要声明;只有重新赋值(即让名字绑定到新对象)才需要 global / nonlocal。详见 4.2 函数:参数传递、默认值与作用域
。
类与继承
class Animal:
kind = "animal" # 类属性,所有实例共享
def __init__(self, name):
self.name = name # 实例属性
def speak(self):
return f"{self.name} makes a sound"
class Dog(Animal):
def speak(self): # 覆写父类方法
return f"{self.name} barks"
>>> Dog("Rex").speak(), Dog.kind, Animal.kind
('Rex barks', 'animal', 'animal')
>>> issubclass(Dog, Animal), isinstance(Dog("Rex"), Animal)
(True, True)
| 概念 | 写法 | 要点 |
|---|---|---|
| 实例方法 | def m(self) | 首个参数是 self |
| 类方法 / 静态方法 | @classmethod / @staticmethod | 首个参数分别是 cls / 无 |
| 属性 | @property | 用访问字段的语法调用方法 |
| 继承 | class B(A) | 单继承;多继承按 MRO 顺序查找 |
| 调用父类 | super().m() | 协作式继承的正确写法 |
| 数据类 | @dataclass | 自动生成 __init__ / __repr__ / __eq__ |
属性查找顺序由 MRO(方法解析顺序)决定,可用 Cls.__mro__ 查看。类机制与 dataclass 见 6.1 类、实例与属性查找(MRO)
与 6.2 继承、组合与 dataclass
。
异常语法
def parse(v):
try:
return int(v)
except ValueError as e:
return f"bad: {e}"
except (TypeError, OverflowError):
return "wrong type"
else:
... # 没有异常时执行
finally:
... # 无论如何都执行,用于释放资源
| 子句 | 何时执行 | 要点 |
|---|---|---|
try | 始终 | 放可能出错的代码 |
except E as e | 抛出匹配的异常 | 可写多个,从上到下匹配 |
else | try 未抛异常时 | 放「成功之后」的逻辑 |
finally | 无论如何 | 清理资源;其中不要写 return |
3.11+ 支持 except* 与 ExceptionGroup,一次处理多个异常;3.14 起 except 可以省略括号(PEP 758)。自定义异常、异常链与 raise ... from 见 7.1 异常层次与 try/except/else/finally
与 7.2 自定义异常、异常链与错误设计
。
match 语句(3.10+)
match 做的是结构化模式匹配,不是简单的值相等:
def describe(v):
match v:
case int():
return "int"
case str() if v == "a":
return "str-a"
case [x, y]:
return f"pair {x},{y}"
case {"type": "point", "x": x, "y": y}:
return f"point {x},{y}"
case _:
return "other"
>>> describe(1), describe("a"), describe([1, 2]), describe({"type": "point", "x": 1, "y": 2})
('int', 'str-a', 'pair 1,2', 'point 1,2')
| 模式 | 写法 | 匹配对象 |
|---|---|---|
| 字面量 | case 1: / case "a": | 相等即匹配 |
| 捕获 | case x: | 匹配任何值并绑定到 x |
| 通配 | case _: | 匹配任何值、不绑定 |
| 类型 | case int(): | 类型检查 |
| 序列 | case [a, b]: | 定长序列解构 |
| 映射 | case {"k": v}: | 字典含该键 |
| 守卫 / 或模式 | case x if x > 0: / case 1 | 2 | 3: | 附加条件 / 任一匹配 |
顺序自上而下,第一个匹配的分支生效,因此具体的模式要写在宽泛的模式前面。
类型注解语法(含 PEP 695)
def greet(name: str, times: int = 1) -> str:
return (name + " ") * times
x: int | None = None # 3.10+ 用 | 表示联合
pairs: list[tuple[str, int]] = []
# PEP 695(3.12+):类型别名与泛型用新语法
type Vector = list[float]
def first[T](xs: list[T]) -> T:
return xs[0]
class Stack[T]:
def __init__(self) -> None:
self._items: list[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T:
return self._items.pop()
| 写法 | 版本 | 说明 |
|---|---|---|
x: int | 3.6+ | 变量 / 参数 / 返回值注解 |
int | None | 3.10+ | 联合类型,替代 Optional[int] |
list[int] / dict[str, int] | 3.9+ | 内置容器可直接下标 |
type X = ... | 3.12+ | 显式类型别名(PEP 695) |
class C[T]: / def f[T]() | 3.12+ | 泛型参数写在名字后 |
注解不参与运行时(3.14 起默认延迟求值),只是给类型检查器看的。类型语法与工具链见 9.1 类型注解语法与 pyright / mypy 与 9.2 泛型、Protocol、TypedDict 与 PEP 695 。
常用内置函数速查
| 函数 | 作用 | 示例 |
|---|---|---|
len(x) | 长度 | len("abc") → 3 |
range(a, b, step) | 整数序列 | list(range(0, 5, 2)) → [0, 2, 4] |
enumerate(it, start) | 带下标遍历 | list(enumerate("ab")) → [(0,'a'),(1,'b')] |
zip(a, b) | 并行遍历 | list(zip([1,2],"ab")) |
sorted(it, key, reverse) | 返回新排序列表 | sorted([3,1,2]) → [1,2,3] |
reversed(seq) | 反向迭代器 | list(reversed([1,2])) → [2,1] |
sum(it, start) | 求和 | sum([1,2,3]) → 6 |
min(it, key) / max(it, key) | 最值 | max([1,2], key=lambda x: -x) → 1 |
any(it) / all(it) | 是否存在真 / 是否全真 | any([0, ""]) → False |
map(f, it) / filter(f, it) | 逐元素映射 / 按条件过滤 | list(map(str, [1,2])) → ['1','2'] |
abs(n) / round(n, d) | 绝对值 / 四舍五入 | round(3.14159, 2) → 3.14 |
isinstance(x, T) | 类型判断 | isinstance(1, int) → True |
print(*objs, sep, end) | 打印 | print(1, 2, sep="-") → 1-2 |
f-string 格式说明符
格式串写作 {值:[填充][对齐][符号][宽度][,][.精度][类型]}:
| 写法 | 结果 | 说明 |
|---|---|---|
f"{x:.2f}" | 3.14 | 保留两位小数 |
f"{x:>8}" / f"{x:<8}" / f"{x:^8}" | 右 / 左 / 居中 | 宽度对齐 |
f"{n:#x}" | 0xff | 十六进制,带 0x 前缀 |
f"{n:08b}" | 00001010 | 二进制,宽度 8 补零 |
f"{p:.1%}" | 25.6% | 百分比 |
f"{n:,}" | 1,234,567 | 千分位分隔 |
f"{x:g}" / f"{x:e}" | 3 / 1.000000e+10 | 通用格式 / 科学计数法 |
f"{s!r}" | 'Ada' | 用 repr 而非 str |
>>> name, score = "Ada", 3.14159
>>> f"{name} got {score:.2f}, hex {255:#x}, pct {0.256:.1%}, comma {1234567:,}"
'Ada got 3.14, hex 0xff, pct 25.6%, comma 1,234,567'
3.14 起还新增了模板字符串 t"..."(PEP 750),用于把插值前的结构保留给下游处理,语法与 f-string 类似但返回 Template 对象。
小结
- 语法速查的价值在于「定位」而非「理解」:先用表找到写法,再回正文看推导。
- 数值上记两条:
//向下取整、浮点有精度误差;需要精确十进制时用decimal。 - 容器选型只问一句「查得频繁吗」——频繁就把
list换成set/dict,in的复杂度从 O(n) 降到 O(1)。 - 函数参数记顺序「位置 → 默认 →
*args→ 仅关键字 →**kw」,并永远不要用可变对象当默认值。 - 作用域只记一句:只读取外层变量无需声明,重新赋值才需要
global/nonlocal。 match是结构化匹配而非值比较;类型注解不参与运行时。附录 B 会在这份语法表之上,继续整理标准库常用模块。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。