收银机导出一串订单,Maya 想按每杯单价排序。为一行比较专门写个具名函数,好像有点小题大做。lambda 什么时候才值得出场?
lambda 是一个小型匿名函数。map 和 filter 会把函数应用到序列上,但在 Python 3 中返回的是惰性迭代器。想查看全部结果时,先转成列表。操作很简单时,推导式往往更清楚。 你还会看到 lambda 的延迟绑定、一次性迭代器,以及用 key 代替 map 后再排序。
lambda 是短函数
lambda 参数: 表达式 可以不用 def 代码块就创建函数。它适合作为一行规则传给另一个函数。如果逻辑需要名字、多个步骤或文档字符串,就改用 def。
double = lambda n: n * 2
print(double(4))
print((lambda a, b: a + b)(2, 3))小型匿名函数
map 转换每个元素
map(function, iterable) 会对每个元素调用一次函数。Python 3 中结果是迭代器,所以要用 list() 包起来才能打印全部值。原序列不会被修改。
nums = [1, 2, 3]
print(list(map(lambda n: n + 1, nums)))
print(nums)惰性的 map
filter 保留匹配项
filter(predicate, iterable) 只保留谓词返回 True 的元素。谓词可以是 lambda,也可以是具名函数。打印或索引前,先把结果转成列表。
nums = [1, 2, 3, 4]
even = filter(lambda n: n % 2 == 0, nums)
print(list(even))保留符合条件的值
lambda 在调用时才查变量
lambda 在被调用时才查找自由变量,而不是创建时。循环里创建的多个 lambda 都引用同一个 n,就都会看到最后的值。需要各自保存当前值时,用默认参数捕获。
funcs = [lambda: n for n in range(3)]
print([fn() for fn in funcs])
fixed = [lambda n=n: n for n in range(3)]
print([fn() for fn in fixed])用默认参数绑定当前循环值
map 和 filter 只能消费一次
map() 和 filter() 返回迭代器,不是列表。消费完就耗尽。需要查看或重复使用时转成列表;不需要时,直接交给 sum() 或 any(),它们也只消费一次。
numbers = map(lambda n: n * 2, [1, 2, 3])
print(list(numbers))
print(list(numbers))
filtered = filter(lambda n: n > 1, [1, 2, 3])
print(any(filtered))
print(any(filtered))耗尽的迭代器不会重新开始
用 key,不要先 map 再排序
只需要极值或顺序时,把 key 函数直接交给 min、max 或 sorted。单独构造一个映射列表会多一步,还可能丢掉原记录。lambda 只写一个短表达式;规则需要名字时改用 def。
orders = [("latte", 4.5), ("tea", 3.0), ("mocha", 5.0)]
cheapest = min(orders, key=lambda item: item[1])
names = sorted(orders, key=lambda item: item[1], reverse=True)
print(cheapest)
print([name for name, price in names])保留记录,传入规则
本课要点
- lambda 用来创建小型匿名函数。
- map 对每个元素应用函数,并返回迭代器。
- filter 保留谓词为真的元素。
- 列表推导式通常比 map 或 filter 更容易读。
- lambda 延迟绑定;迭代器只消费一次;key 函数能保留原记录。
常见错误
- 直接打印 map 或 filter 对象,却期待看到列表。
- 逻辑很复杂时仍然硬写 lambda,而不是用具名函数。
- 忘记 map 和 filter 在被消费前是惰性的。
- 对映射后的价格列表排序,结果丢掉了饮料名。
用 map 和 filter 把 [1, 2, 3, 4, 5] 中的偶数平方。
动手试试
改改变量、先预测输出,再运行代码。第一次点击“运行代码”时会下载 Python 运行时,可能需要几秒钟。
练习本课
12 道题,作答后立即看到解释。