跳到主要内容

现代 Python 你应该知道的 10 个特性

· 阅读需 4 分钟
Destiny
Python 学习者

很多人写 Python 还停留在 3.6 时代的写法:Optional[int]os.path.joinif-elif-else 一长串。其实从 3.10 开始,Python 已经悄悄变成了一门「看起来很像新语言」的语言。下面这 10 个特性,是我在日常代码里几乎天天都会用到的。本教程默认 Python 3.12+,所以放心大胆地用。

1. match-case:结构化模式匹配(3.10)

不再是简单的 switch,它支持解构:

def describe(point: tuple[int, int]) -> str:
match point:
case (0, 0):
return "原点"
case (x, 0):
return f"在 x 轴上,x={x}"
case (0, y):
return f"在 y 轴上,y={y}"
case (x, y):
return f"普通点 ({x}, {y})"

print(describe((3, 0))) # 在 x 轴上,x=3
提示

match-case 还能匹配类实例、字典、序列,配合「守卫表达式」(case Point(x, y) if x == y) 非常强大。

2. 海象运算符 :=(3.8,但 3.10 才流行起来)

赋值的同时返回值,省掉一次重复调用:

import re

if (m := re.search(r"\d+", "订单号: 9527")) is not None:
print(f"提取到数字:{m.group()}") # 提取到数字:9527

3. 类型注解 X | Y(3.10)

终于不用再写 Union[int, str]Optional[int]

def find_user(user_id: int) -> dict | None:
if user_id == 1:
return {"name": "destiny"}
return None

# 等价于 Optional[dict] / Union[dict, None]

4. dataclass + slots(3.10)

一行 slots=True 让 dataclass 用 __slots__,省内存又禁止动态属性:

from dataclasses import dataclass

@dataclass(slots=True)
class Point:
x: float
y: float

p = Point(1.0, 2.0)
# p.z = 3.0 # AttributeError,防止手滑加错字段

5. f-string 嵌套与调试输出(3.12)

3.12 终于支持在 f-string 的 {} 里再写 f-string,=调试语法也更好用:

user = {"name": "destiny", "level": 5}
width = 12

# 嵌套 f-string
print(f"{f"{user['name']:^{width}}"}") # destiny

# 调试语法 = 直接打印变量名和值
print(f"{user=}") # user={'name': 'destiny', 'level': 5}

6. TaskGroup:结构化并发(3.11)

asyncio.gather 的更安全替代,子任务出错能一起取消:

import asyncio

async def fetch(url: str) -> str:
await asyncio.sleep(0.1)
return f"data from {url}"

async def main() -> None:
async with asyncio.TaskGroup() as tg:
t1 = tg.create_task(fetch("api/a"))
t2 = tg.create_task(fetch("api/b"))
print(t1.result(), t2.result())

asyncio.run(main())
注意

TaskGroup 一旦有任何子任务抛错,会取消其它所有子任务,并抛出 ExceptionGroup。这正是我们想要的行为——并发任务要么一起成功,要么一起失败。

7. ExceptionGroup / except*(3.11)

为并发场景设计的「一组异常一起处理」:

def risky(x: int) -> None:
if x < 0:
raise ValueError(f"负数:{x}")

try:
risky(-1)
risky(-2)
except* ValueError as eg:
for e in eg.exceptions:
print("处理:", e)

8. type 语句:定义类型别名(3.12)

TypeAlias 的语法糖,还能定义泛型别名:

type Vector = list[float]
type Matrix[T] = list[list[T]]

def norm(v: Vector) -> float:
return sum(x * x for x in v) ** 0.5

# 泛型别名
m: Matrix[int] = [[1, 2], [3, 4]]

9. pathlib.Path.walk()(3.12)

终于不用再写 os.walk,而且能拿到 dir_entry 做更高效过滤:

from pathlib import Path

root = Path(".")
for dirpath, dirnames, filenames in root.walk():
if "__pycache__" in dirnames:
dirnames.remove("__pycache__") # 剪枝,不再深入
for name in filenames:
if name.endswith(".py"):
print(dirpath / name)
提示

Path.walk() 还支持 top_down=False,自底向上遍历——删空目录时非常有用。

10. Self 类型 & override 装饰器(3.11/3.12)

写「返回自己类型」的方法不再痛苦:

from typing import Self, override

class Shape:
def scale(self, factor: float) -> Self:
return self # 子类调用会自动返回子类类型

class Circle(Shape):
def __init__(self, r: float) -> None:
self.r = r

@override
def scale(self, factor: float) -> Self:
self.r *= factor
return self

@override 会在父类没有同名方法时静态报错,防止手滑写错方法名。

小结

这 10 个特性里,真正改变我写代码习惯的是三个:match-case(替代 if-elif 链)、X | Y 类型注解(让类型写起来不痛苦)、TaskGroup(让并发代码更安全)。其余几个则是「锦上添花」,但堆在一起,已经让 Python 3.12 读起来像一门全新的语言。

如果你还在用 3.9 写代码,强烈建议升级到 3.12——体验的提升不只是「快一点」,而是「写法完全不同」。