Lambda 与短小可调用对象
Lambda 表达式用于创建仅包含单个表达式的匿名函数:
by_last_name = lambda person: person.last_name.casefold()
people.sort(key=by_last_name)
它的最佳用途是作为直接传递给 API 的简短可调用对象,尤其是 key= 参数。如果逻辑需要文档字符串(docstring)、类型注解、复用、多步骤处理,或者需要更有意义的错误堆栈,具名函数会更清晰。
records.sort(key=lambda row: (row.priority, row.created_at))
对于常规的转换和过滤,优先使用列表推导式或生成器表达式:
active_names = [user.name for user in users if user.active]
total = sum(order.amount for order in orders)
相比嵌套 map、filter 和 lambda,推导式通常能更直观地表达意图。只有当已有一个具名函数能准确表达操作时,map 才更有用武之地。
闭包陷阱
函数捕获的是变量名,而非变量值,变量的值在函数执行时才被查找。因此,在循环中创建回调函数时容易踩中“晚绑定”陷阱:
callbacks = [lambda: index for index in range(3)]
# 每个回调都返回 2。
如果需要捕获循环当前的值,应显式通过默认参数捕获:
callbacks = [lambda index=index: index for index in range(3)]
默认参数在函数创建时求值。对于逻辑稍复杂的回调,使用小型工厂函数或 functools.partial 往往比 lambda 更易读、更易解释。
不要将 lambda 语法等同于函数式编程中的“纯函数”。Lambda 和具名函数一样,完全可以调用有状态函数或修改对象。