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"包装器既要转发关键字参数,也要返回原函数值;打印的耗时不固定,不对其数值做断言。参考未执行。
继续阅读
- 开发实践
- 排错
- 开发实践