Skip to content

Python 推导式、装饰器与资源管理 ​

推导式与迭代器 ​

先读 函数与闭包、列表 和 异常处理。简单映射、过滤可写为推导式,复杂分支继续用循环。

python
numbers = [1, 2, 3, 4]
squares = [n * n for n in numbers if n % 2 == 0]
by_number = {n: n * n for n in numbers}
unique = {name.lower() for name in ["Alice", "ALICE"]}
assert squares == [4, 16]
assert by_number[3] == 9
assert unique == {"alice"}

map、filter 返回迭代器,遍历后会耗尽;要列表时显式用 list(...)。生成器表达式 (n * n for n in numbers) 也可按需计算,适合接给 sum 等消费函数。

lambda ​

lambda 只有一个表达式,常用于简短回调。需要命名、文档或多步逻辑时用 def。

python
people = [{"name": "Bob", "age": 30}, {"name": "Alice", "age": 20}]
assert sorted(people, key=lambda person: person["age"])[0]["name"] == "Alice"

装饰器 ​

@decorate 把函数交给可调用对象处理,再把处理结果绑定回函数名,近似于 func = decorate(func)。常见包装器用 functools.wraps 保留被包装函数的名称与文档。

python
from functools import wraps
from time import perf_counter


def timed(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = perf_counter()
        try:
            return func(*args, **kwargs)
        finally:
            print(f"{func.__name__}: {perf_counter() - start:.6f}s")
    return wrapper


@timed
def add(a, b):
    return a + b


assert add(2, 3) == 5
assert add.__name__ == "add"

这是同步函数计时示例,不能直接用于准确测量协程等待过程;异步包装需要 async def 和 await。

with 管理资源 ​

with 调用上下文管理协议,在退出代码块时执行清理逻辑。文件上下文管理器会关闭文件,包括块内发生异常时;不是所有对象都能直接放在 with 后。

python
from io import StringIO

with StringIO("hello\nworld\n") as stream:
    lines = stream.read().splitlines()
assert lines == ["hello", "world"]
assert stream.closed

实际文件使用 with open("notes.txt", encoding="utf-8") as stream:,文件必须存在。文件处理的完整示例见 标准库。

练习 ​

把“循环去空白并过滤空行”改写为推导式,确认结果相同;给一个有关键字参数的函数加 @timed,确认返回值与名称保留。下一步读 类与实例。

参考解答 ​

去空白的局部参考为 cleaned = [line.strip() for line in [" a ", " ", " b"] if line.strip()],预期 ["a", "b"]。先用逐行循环得出同样结果再比较。沿用上文 timed 定义,将其用于以下函数:

python
@timed
def greet(name, *, prefix="Hi"):
    return f"{prefix}, {name}"


assert greet("Ada", prefix="Hello") == "Hello, Ada"
assert greet.__name__ == "greet"

包装器既要转发关键字参数,也要返回原函数值;打印的耗时不固定,不对其数值做断言。参考未执行。

继续阅读