Python中的奇技淫巧
1. 海象运算符 :=
(Python 3.8+)
用途说明:在表达式中直接赋值并返回值,减少冗余语句。例如在 if
语句中计算长度并使用,无需先单独计算赋值。
示例:
if (n := len(data)) > 10:
print(f"数据量为 {n}")
上例中 (n := len(data))
在判断时给 n
赋值,同时作为整个表达式的值。
2. 格式化字符串(f-strings)(Python 3.6+)
用途说明:在字符串前加 f
或 F
后引号,在大括号中嵌入 Python 表达式,简洁地进行格式化。支持任意表达式、格式说明符等。
示例:
name = "Alice"
age = 30
print(f"{name} 的年龄是 {age} 岁") # Alice 的年龄是 30 岁
f-string 是 Python 3.6 引入的语言特性,相比 %
格式化和 str.format()
更直观且性能更优。
3. f-string 调试表达式(Python 3.8+)
用途说明:在 f-string 表达式末尾添加 =
,可以打印表达式本身和结果,便于调试。
示例:
value = 42
print(f"{value=}") # 输出 "value=42"
这种语法自 3.8 版起可用,能快速显示变量名和其值。
4. 数字字面量中的下划线(Python 3.6+)
用途说明:在整数或浮点数字面量中使用下划线 _
作为分隔符,增强可读性,不影响值。
示例:
million = 1_000_000
hex_val = 0xCAFE_F00D
binary = 0b_1010_1011
以上代码合法,自 Python 3.6 起支持在数字中任意位置加 _
,可显著提高长数字的可读性。
5. 字典合并运算符 |
和 |=
(Python 3.9+)
用途说明:可以使用 |
将两个字典合并生成新字典,用 |=
更新原字典而非返回。
示例:
a = {'x':1, 'y':2}
b = {'y':3, 'z':4}
c = a | b # {'x':1, 'y':3, 'z':4}
a |= b # a 现在也变成 {'x':1, 'y':3, 'z':4}
这在 Python 3.9 以后成为内置语法,无需 copy()
和 update()
,写法简洁明了。
6. 内置容器类型可作泛型(Python 3.9+)
用途说明:typing
模块逐步支持直接使用内置类型来表示泛型。Python 3.9 以后,列表、字典、集合等类型都可以直接用中括号标注类型。
示例:
names: list[str] = ["Alice", "Bob"] # 等价于 typing.List[str]
point: dict[str, float] = {"x":0.0, "y":1.0}
PEP 585 使得 list[int]
等写法生效,不再需要导入 typing.List
,使代码更简洁。
7. 新增字符串去除前后缀方法(Python 3.9+)
用途说明:提供 str.removeprefix(prefix)
和 str.removesuffix(suffix)
方法,直接去除字符串的固定前缀或后缀,返回去除后的新字符串,如果不存在则返回原字符串。
示例:
s = "unittest"
print(s.removeprefix("unit")) # 输出 "test"
print(s.removesuffix("test")) # 输出 "unit"
这两个方法从 Python 3.9 开始可用,避免了手动检查索引或使用正则等繁琐步骤。
8. 类型提示中的联合类型 X | Y
(Python 3.10+)
用途说明:使用 |
运算符简写联合类型,比如 int | None
相当于 Optional[int]
,无需使用 typing.Union
。
示例:
def greeting(name: str | None) -> str:
return f"Hello {name}" if name else "Hello world"
Python 3.10 引入此语法,使类型提示更自然简洁。
9. 用户定义类型守卫(TypeGuard)(Python 3.10+)
用途说明:typing.TypeGuard
用于自定义类型检查函数,让类型检查器理解某个函数验证参数类型后,后续代码对类型更精确。
示例:
from typing import TypeGuard
def is_str_list(val: list[object]) -> TypeGuard[list[str]]:
return all(isinstance(x, str) for x in val)
values: list[object] = ["a", "b", 3]
if is_str_list(values):
# 此处 values 被推断为 list[str]
print(values[0].upper())
Python 3.10 引入 PEP 647 提供 TypeGuard
,上述例子中 is_str_list
让类型检查器知道在 if
分支中 values
中元素全为 str
。
10. yield from
生成器委托(Python 3.3+)
用途说明:yield from
可以把一个子生成器的所有产出直接转发到外层生成器,用于简化嵌套迭代、代理生成器等。
示例:
def subgen():
for i in range(3):
yield i
def gen():
yield from subgen()
yield 3
print(list(gen())) # [0, 1, 2, 3]
自 Python 3.3 起支持,大大简化了从一个生成器顺序产出值的代码编写。
11. 原生协程语法 async def
/ await
(Python 3.5+)
用途说明:使用 async def
定义异步协程函数,使用 await
等待异步操作。使异步编程写法与同步类似,可读性高。
示例:
import asyncio
async def hello():
await asyncio.sleep(1)
print("Hello")
async def main():
await asyncio.gather(hello(), hello())
asyncio.run(main())
Python 3.5 引入 PEP 492 后,原生支持 async/await
关键字,无需第三方库即可编写协程代码。
12. 异步推导式(Python 3.6+)
用途说明:可以在异步环境中使用 [...]
、{...}
和 (...)
推导式配合 async for
和 async if
来创建异步生成器、列表或集合。
示例:
async def async_iter():
for i in range(3):
yield i
result = [i * 2 async for i in async_iter() if i % 2 == 1]
print(result) # [2, 6]
PEP 530 在 Python 3.6 中加入此功能,使得异步数据处理更为简洁,不必显式循环累加。
13. 异步生成器(Python 3.6+)
用途说明:在 async def
函数中使用 yield
,创建异步生成器,可在异步函数之间逐步产出值并用 async for
迭代。
示例:
async def agen(n):
for i in range(n):
yield i
async def consume():
async for v in agen(3):
print(v)
asyncio.run(consume()) # 输出 0,1,2
14. contextlib.suppress
(Python 3.4+)
用途说明:contextlib.suppress(*exceptions)
创建一个上下文管理器,自动忽略指定的异常,使代码更简洁。
示例:
from contextlib import suppress
with suppress(FileNotFoundError):
os.remove("not_exists.txt") # 文件不存在也不会抛出异常
15. contextlib.redirect_stdout
/redirect_stderr
(Python 3.4+)
用途说明:重定向标准输出或错误流到指定文件或对象,非常方便进行输出捕获。
示例:
from contextlib import redirect_stdout
import io
buf = io.StringIO()
with redirect_stdout(buf):
print("This is captured")
print("Captured:", buf.getvalue())
16. contextlib.nullcontext
(Python 3.7+)
用途说明:提供一个什么都不做的上下文管理器,可作为条件性 with
的占位符。当不需要实际的资源管理时使用,保持代码结构一致。
示例:
from contextlib import nullcontext
use_context = False
cm = open("file.txt") if use_context else nullcontext("dummy")
with cm as f:
print(f) # 如果 use_context False,f 就是字符串 "dummy"