0%

Python3 高阶函数:函数式编程的核心工具

Python 高阶函数:把函数当”变量”用,代码能少写一半

写 Python 的时候,你可能已经不经意间用过高阶函数了——比如 map()filter()sorted()key 参数。它们的特点是:把一个函数作为参数传给另一个函数

说白了,高阶函数就是”能操作函数的函数”。就像你把一个数据传给函数处理一样,高阶函数让你把处理逻辑本身传给另一个函数。

这东西为什么有用?因为它把”做什么”和”怎么做”分开了——你告诉我规则,我按规则处理数据。

函数也是”值”,可以传来传去

在 Python 里,函数跟数字、字符串一样,也是对象。你可以把它赋值给变量、放进列表、当成参数传给别的函数。

1
2
3
4
5
6
7
8
9
10
def square(x):
return x ** 2

# 函数可以赋值给变量
f = square
f(5) # 25

# 函数可以放进列表
funcs = [square, abs, len]
funcs[0](4) # 16

能当参数传,就有了高阶函数:

1
2
3
4
def apply(func, value):
return func(value)

apply(square, 5) # 25

这个 apply 就是高阶函数——它接收了一个函数参数,在内部调用了它。

map:挨个处理,批量转换

map(func, iterable)func 应用到可迭代对象的每一个元素上,返回一个新的迭代器。

把列表里每个数字都平方:

1
2
3
nums = [1, 2, 3, 4]
squares = map(lambda x: x ** 2, nums)
list(squares) # [1, 4, 9, 16]

把字符串列表转成整数:

1
2
3
str_nums = ["12", "34", "56"]
int_nums = map(int, str_nums)
list(int_nums) # [12, 34, 56]

这里 int 本身就是一个函数,直接传给 map,省了写 lambda。

两个列表对应相加:

1
2
3
4
a = [1, 2, 3]
b = [4, 5, 6]
sums = map(lambda x, y: x + y, a, b)
list(sums) # [5, 7, 9]

map 最多可以传多个可迭代对象,函数接收几个参数就传几个列表。

filter:按条件筛选

filter(func, iterable) 对每个元素执行 func,只保留返回 True 的那些。

只保留偶数:

1
2
3
nums = [1, 2, 3, 4, 5, 6]
evens = filter(lambda x: x % 2 == 0, nums)
list(evens) # [2, 4, 6]

过滤掉空字符串:

1
2
3
names = ["Alice", "", "Bob", None, "Charlie"]
valid = filter(lambda x: x, names) # None 和空字符串都是 False
list(valid) # ['Alice', 'Bob', 'Charlie']

这里 lambda x: x 就是”保留真值”,空字符串、None、0 都会被过滤掉。

reduce:逐个累加,归并成一个

reduce(func, iterable) 把前两个元素传给 func,结果再跟第三个元素继续运算,最终归并成一个值。

reduce 不在内置命名空间里,需要从 functools 导入。

求和:

1
2
3
4
5
from functools import reduce

nums = [1, 2, 3, 4]
reduce(lambda x, y: x + y, nums) # 10
# 过程:1+2=3 → 3+3=6 → 6+4=10

求乘积:

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
2
3
words = ["apple", "banana", "cherry", "date"]
sorted(words, key=lambda x: len(x))
# ['date', 'apple', 'cherry', 'banana']

按绝对值排序:

1
2
3
nums = [-3, 1, -2, 5]
sorted(nums, key=lambda x: abs(x))
# [1, -2, -3, 5]

按对象的某个属性排序:

1
2
3
4
5
6
7
users = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 30},
{"name": "Charlie", "age": 22}
]
sorted(users, key=lambda u: u["age"])
# 按年龄从小到大排

key 函数的返回值可以是任意类型,只要能比较大小就行。

map/filter 和列表推导式,用哪个?

很多场景下,mapfilter 能做的事,列表推导式也能做。怎么选?

map/filter 列表推导式
风格 函数式,适合链式调用 声明式,更像自然语言
性能 略快(惰性求值) 略慢(立即生成列表)
可读性 简单场景 ok,复杂场景差 大多数场景更直观
条件过滤 需要 filter 直接支持 if

例子对比:

1
2
3
4
5
6
7
8
9
10
11
# map
list(map(lambda x: x ** 2, range(10)))

# 列表推导式
[x ** 2 for x in range(10)]

# filter
list(filter(lambda x: x % 2 == 0, range(10)))

# 列表推导式(带 if)
[x for x in range(10) if x % 2 == 0]

我的建议: 简单场景两者都可,复杂逻辑用列表推导式更清晰。map+filter 的优势在于可以链式组合,比如:

1
2
3
4
# 先用 filter 过滤,再用 map 转换
scores = ["90", "85", "abc", "95", "78"]
valid = map(int, filter(lambda x: x.isdigit(), scores))
list(valid) # [90, 85, 95, 78]

函数作为返回值:闭包和装饰器

高阶函数不光能收函数,还能返回函数

生成一个”乘以N”的函数:

1
2
3
4
5
6
7
8
9
10
def make_multiplier(n):
def multiplier(x):
return x * n
return multiplier

double = make_multiplier(2)
triple = make_multiplier(3)

double(5) # 10
triple(5) # 15

这个模式叫”闭包”——内层函数记住了外层函数的参数 n,即使外层函数已经执行完了。

装饰器就是高阶函数的典型应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
def log(func):
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper

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

add(2, 3)
# 调用 add
# 5

@log 等价于 add = log(add)——把 add 函数传给 log,得到一个增强版本再赋值回去。

实战:数据处理流水线

把几个高阶函数串起来,处理一批数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from functools import reduce

# 原始数据:姓名:分数
raw = ["Alice:90", "Bob:85", "Charlie:abc", "David:95", "Eve:78"]

# 解析:过滤掉格式错误的
def parse(s):
try:
name, score = s.split(":")
return (name, int(score))
except:
return None

# 链式处理
valid = filter(None, map(parse, raw)) # 去掉 None
scores = map(lambda x: x[1], valid) # 只取分数
total = reduce(lambda x, y: x + y, scores) # 求和

print(total) # 348

注意:mapfilter 返回的是迭代器,只能遍历一次。如果后面还需要用,要转成列表保存下来。

欢迎关注我的其它发布渠道