Python 3.8
海象运算符
旧语法
1 2 3
| n = len(data) if n > 0: print(n)
|
新语法
1 2
| if (n := len(data)) > 0: print(n)
|
仅位置参数
旧语法
1 2 3 4
| def add(a, b): return a + b
add(a=1, b=2)
|
本没有什么问题,但是假设add函数变化了参数名,例如将a,b改成了x,y,那么情况将有所不同
1 2 3 4
| def add(x, y): return x + y
add(a=1, b=2)
|
将会发生错误。因此引入了仅位置参数。
新语法
标志位(/)前的参数必须以特定位置顺序传入,而不能通过变量名传入。与之相对的是仅通过变量名传入(*),其后的变量只能通过变量名传入参数。对应的代码如下
1 2 3 4 5 6 7 8
| def f(a, b, /, c, d, *, e): pass
f(1, 2, 3, 4, e=5) f(1, 2, c=3, d=4, e=5)
f(a=1, b=2, c=3, d=4, e=5) f(1, 2, 3, 4, 5)
|
Python 3.9
字典合并
旧语法
想要合并两个字典,最普通的方案为:
或
1 2
| c = a.copy() c.update(b)
|
新语法
Python 3.10
模式匹配
模式匹配的语法较多,以下是一些常见的用法:
1. 基本匹配(值匹配)
旧写法:
1 2 3 4
| if x == 1: ... elif x == 2: ...
|
新写法:
1 2 3 4 5
| match x: case 1: ... case 2: ...
|
同时,可以使用|连接多个值
1 2 3 4 5 6 7
| match status_code: case 200 | 201: print("Success") case 404: print("Not Found") case _: print("Unknown Status")
|
2. 序列解构与通配符
1 2 3 4 5 6 7 8
| command = ["move", 10, 20] match command: case ["quit"]: exit() case ["move", x, y]: print(f"移动到 {x}, {y}") case ["drop", *items]: print(f"丢弃了 {len(items)} 个物品")
|
3. 字典匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| match user_data: case {"name": name, "admin": True}: print(f"管理员权限:{name} 正在进入后台")
case {"name": name, "email": email}: print(f"普通用户:{name},联系方式:{email}")
case {"name": name}: print(f"仅获取到用户名:{name}")
case _: print("未识别的用户数据")
|
4. 类型匹配与变量绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| match data: case int(n): print(f"接收到整数: {n}, 它的平方是 {n**2}") case str(s): print(f"接收到字符串,长度为: {len(s)}") case float(f) if f < 0: print(f"接收到负浮点数: {f}")
case _: print("未知类型")
|
5. 进阶:模式守卫
1 2 3 4 5
| match x: case [a, b] if a == b: print("两个元素相等") case [a, b]: print("两个元素不等")
|
6. 进阶:绑定变量
1 2 3
| match data: case [int(), int()] as coords: print(f"坐标对是: {coords}")
|
Python 3.11
异常组
旧语法
过去,当我们在并发编程(如 asyncio)中同时遇到多个错误时,只能捕获一个,或者把它们打包成一个普通的异常列表,处理起来非常不直观。
1 2 3 4 5
| try: raise ValueError("发生了一些错误") except ValueError as e: print(f"捕获到异常: {e}")
|
新语法
引入了 ExceptionGroup 以及专属的 except* 语法糖,允许一次性抛出多个异常,并根据异常类型分别进行捕获。
1 2 3 4 5 6 7 8 9
| try: raise ExceptionGroup( "多个任务失败", [ValueError("值错误"), TypeError("类型错误")] ) except* ValueError: print("处理所有的 ValueError") except* TypeError: print("处理所有的 TypeError")
|
Python 3.12
f-string 语法
旧语法
在 3.12 之前,f-string 虽然好用,但有很多让人抓狂的限制。比如:不能在花括号内复用外层的引号、不能在花括号内使用反斜杠(如 \n)。
1 2 3 4 5 6 7 8
| employee = {"name": "Alice"}
print(f"Employee: {employee['name']}")
words = ['Hello', 'World']
nl = '\n' print(f"Words: {nl.join(words)}")
|
新语法
3.12 重写了 f-string 的解析器,彻底解除了这些限制。可以直接复用引号,甚至在里面写多行表达式和转义字符。
1 2 3 4 5
| employee = {"name": "Alice"} print(f"Employee: {employee["name"]}")
words = ['Hello', 'World'] print(f"Words: {'\n'.join(words)}")
|
泛型语法 (Type Parameter Syntax)
旧语法
以前写泛型提示,必须引入 TypeVar 并单独声明,显得很啰嗦。
1 2 3 4 5 6
| from typing import TypeVar
T = TypeVar('T')
def get_first(elements: list[T]) -> T: return elements[0]
|
新语法
借鉴了类似 C++ 和 Rust 的语法,现在可以直接在函数名后面使用中括号 [] 声明泛型。
1 2
| def get_first[T](elements: list[T]) -> T: return elements[0]
|
Python 3.13
泛型参数默认值
旧语法
在 3.12 中,泛型不能设置默认类型。如果在某些场景下你想让泛型 T 默认就是 int,是做不到的。
新语法
3.13 允许在定义泛型时使用 = 赋予默认类型。
1 2 3 4 5 6 7 8
| type Box[T = int] = list[T]
my_box: Box = [1, 2, 3]
str_box: Box[str] = ["a", "b"]
|
Python 3.14
模板字符串 (t-strings)
旧语法
如果想自己解析一段带变量的字符串(比如为了防止 SQL 注入、做 HTML 转义),用 f-string 是做不到的,因为它会立刻把字符串求值并拼接死。
新语法
引入了 t”” 前缀。它不会立刻拼接成普通的字符串,而是生成一个 Template 对象,将写的静态文本和动态变量分开保存,方便后续安全处理。
1 2 3 4 5 6 7 8 9
| from string.templatelib import Template
name = "Alice"
t_str = t"Hello {name}, welcome back!"
print(t_str.strings) print(t_str.values)
|