Python 高阶函数:把函数当”变量”用,代码能少写一半
写 Python 的时候,你可能已经不经意间用过高阶函数了——比如 map()、filter()、sorted() 的 key 参数。它们的特点是:把一个函数作为参数传给另一个函数。
说白了,高阶函数就是”能操作函数的函数”。就像你把一个数据传给函数处理一样,高阶函数让你把处理逻辑本身传给另一个函数。
这东西为什么有用?因为它把”做什么”和”怎么做”分开了——你告诉我规则,我按规则处理数据。
函数也是”值”,可以传来传去
在 Python 里,函数跟数字、字符串一样,也是对象。你可以把它赋值给变量、放进列表、当成参数传给别的函数。
1 | def square(x): |
能当参数传,就有了高阶函数:
1 | def apply(func, value): |
这个 apply 就是高阶函数——它接收了一个函数参数,在内部调用了它。
map:挨个处理,批量转换
map(func, iterable) 把 func 应用到可迭代对象的每一个元素上,返回一个新的迭代器。
把列表里每个数字都平方:
1 | nums = [1, 2, 3, 4] |
把字符串列表转成整数:
1 | str_nums = ["12", "34", "56"] |
这里 int 本身就是一个函数,直接传给 map,省了写 lambda。
两个列表对应相加:
1 | a = [1, 2, 3] |
map 最多可以传多个可迭代对象,函数接收几个参数就传几个列表。
filter:按条件筛选
filter(func, iterable) 对每个元素执行 func,只保留返回 True 的那些。
只保留偶数:
1 | nums = [1, 2, 3, 4, 5, 6] |
过滤掉空字符串:
1 | names = ["Alice", "", "Bob", None, "Charlie"] |
这里 lambda x: x 就是”保留真值”,空字符串、None、0 都会被过滤掉。
reduce:逐个累加,归并成一个
reduce(func, iterable) 把前两个元素传给 func,结果再跟第三个元素继续运算,最终归并成一个值。
reduce 不在内置命名空间里,需要从 functools 导入。
求和:
1 | from functools import reduce |
求乘积:
1 | reduce(lambda x, y: x * y, nums) # 24 |
带初始值:
1 | reduce(lambda x, y: x + y, nums, 10) # 20,从10开始加 |
reduce 适合做”聚合类”操作——求和、求积、拼接字符串、找最大值。Python 里这些操作通常有更直接的方式(比如 sum()、max()),但 reduce 的通用性更强,可以处理任意归并逻辑。
sorted:排序规则你来定
sorted(iterable, key=func) 的 key 参数接收一个函数,根据函数的返回值来决定排序顺序。
按字符串长度排序:
1 | words = ["apple", "banana", "cherry", "date"] |
按绝对值排序:
1 | nums = [-3, 1, -2, 5] |
按对象的某个属性排序:
1 | users = [ |
key 函数的返回值可以是任意类型,只要能比较大小就行。
map/filter 和列表推导式,用哪个?
很多场景下,map 和 filter 能做的事,列表推导式也能做。怎么选?
| map/filter | 列表推导式 | |
|---|---|---|
| 风格 | 函数式,适合链式调用 | 声明式,更像自然语言 |
| 性能 | 略快(惰性求值) | 略慢(立即生成列表) |
| 可读性 | 简单场景 ok,复杂场景差 | 大多数场景更直观 |
| 条件过滤 | 需要 filter |
直接支持 if |
例子对比:
1 | # map |
我的建议: 简单场景两者都可,复杂逻辑用列表推导式更清晰。map+filter 的优势在于可以链式组合,比如:
1 | # 先用 filter 过滤,再用 map 转换 |
函数作为返回值:闭包和装饰器
高阶函数不光能收函数,还能返回函数。
生成一个”乘以N”的函数:
1 | def make_multiplier(n): |
这个模式叫”闭包”——内层函数记住了外层函数的参数 n,即使外层函数已经执行完了。
装饰器就是高阶函数的典型应用:
1 | def log(func): |
@log 等价于 add = log(add)——把 add 函数传给 log,得到一个增强版本再赋值回去。
实战:数据处理流水线
把几个高阶函数串起来,处理一批数据:
1 | from functools import reduce |
注意:map 和 filter 返回的是迭代器,只能遍历一次。如果后面还需要用,要转成列表保存下来。