

🧩 说明 :虽然 Python 是多范式语言,但其对函数式编程(Functional Programming) 的支持能让你在处理数据时写出更简洁、声明式的代码。本篇聚焦四个核心工具:
lambda、map()、filter()、functools.reduce(),助你告别冗长循环,提升代码表达力。
你将学会:
- 什么是匿名函数(
lambda)? - 如何用
map批量转换数据? - 如何用
filter精准筛选元素? reduce如何将序列"折叠"为单值?- 何时该用函数式风格?何时该用列表推导式?
1. 函数式编程思想简介
核心理念:
- 函数是一等公民(可赋值、传参、返回)
- 避免改变状态和可变数据(强调不可变性)
- 用表达式 代替语句
💡 Python 并非纯函数式语言,但合理使用函数式工具能让代码更清晰。
2. lambda:匿名函数
用于定义简单、一次性的小函数。
语法
python
lambda 参数: 表达式
示例对比
python
# 普通函数
def square(x):
return x ** 2
# lambda 等价写法
square = lambda x: x ** 2
# 直接使用(常见于高阶函数)
numbers = [1, 2, 3, 4]
squared = list(map(lambda x: x**2, numbers))
print(squared) # [1, 4, 9, 16]
✅ 适用场景:
作为
map/filter/sorted的参数简单逻辑(一行能写完)
❌ 不适用场景:复杂逻辑(应使用普通函数 + 文档字符串)
3. map():批量应用函数
将函数映射到序列的每个元素,返回迭代器。
基本用法
python
# 将字符串转为整数
str_nums = ["1", "2", "3"]
int_nums = list(map(int, str_nums))
print(int_nums) # [1, 2, 3]
# 自定义函数
def to_upper(s):
return s.upper()
words = ["hello", "world"]
upper_words = list(map(to_upper, words))
# 或用 lambda
upper_words = list(map(lambda s: s.upper(), words))
多序列支持
python
# 同时处理两个列表
list1 = [1, 2, 3]
list2 = [10, 20, 30]
result = list(map(lambda x, y: x + y, list1, list2))
print(result) # [11, 22, 33]
⚠️ 注意:
map返回迭代器 ,需用list()转换才能重复使用。
4. filter():按条件筛选
保留使函数返回 True 的元素。
示例
python
# 筛选偶数
numbers = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6]
# 筛选非空字符串
texts = ["apple", "", "banana", " ", "cherry"]
non_empty = list(filter(lambda s: s.strip(), texts))
print(non_empty) # ['apple', 'banana', 'cherry']
🔍
filter也返回迭代器。
5. functools.reduce():累积计算
将序列"折叠"为单个值(需从 functools 导入)。
基本原理
python
from functools import reduce
# 计算累加:((1+2)+3)+4
numbers = [1, 2, 3, 4]
total = reduce(lambda acc, x: acc + x, numbers)
print(total) # 10
# 初始值可选
product = reduce(lambda acc, x: acc * x, [1, 2, 3, 4], 1)
print(product) # 24
实用场景
- 求最大值(虽有
max(),但演示逻辑) - 连接字符串
- 复杂累积逻辑
python
# 连接单词
words = ["Hello", "World", "Python"]
sentence = reduce(lambda a, b: a + " " + b, words)
print(sentence) # Hello World Python
⚠️ 注意 :简单操作(如求和、求积)优先用内置函数
sum()、math.prod()。
6. 函数式 vs 列表推导式:如何选择?
| 特性 | 函数式(map/filter) |
列表推导式 |
|---|---|---|
| 可读性 | 适合简单函数 | 更直观(Pythonic) |
| 性能 | 略快(C 实现) | 接近 |
| 灵活性 | 支持任意函数 | 仅表达式 |
| 内存 | 返回迭代器(省内存) | 直接生成列表 |
对比示例
python
nums = range(10)
# 函数式
result1 = list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, nums)))
# 列表推导式(推荐!)
result2 = [x**2 for x in nums if x % 2 == 0]
# 两者结果相同
assert result1 == result2
✅ 社区共识:
"在 Python 中,列表推导式通常比
map+filter更清晰。"------《流畅的 Python》(Fluent Python)
📌 建议:
- 简单过滤/转换 → 用列表推导式
- 已有命名函数 → 可用
map(func, iterable)- 复杂累积 → 考虑
reduce或普通循环
7. 高级技巧:组合使用
示例:处理学生成绩
python
students = [
{"name": "Alice", "score": 85},
{"name": "Bob", "score": 92},
{"name": "Charlie", "score": 78}
]
# 获取及格学生姓名(>=80),按分数降序
from operator import itemgetter
passed_names = list(map(
lambda s: s["name"],
filter(lambda s: s["score"] >= 80, students)
))
# 但更 Pythonic 的写法:
passed_names = [s["name"] for s in students if s["score"] >= 80]
passed_names.sort(key=lambda name: next(s["score"] for s in students if s["name"] == name), reverse=True)
💡 提示:对于字典排序,可用
operator.itemgetter提升可读性:
python
from operator import itemgetter
top_students = sorted(students, key=itemgetter("score"), reverse=True)
8. 常见陷阱与注意事项
| 问题 | 解决方案 |
|---|---|
忘记 list() 转换 |
map/filter 返回迭代器,只能遍历一次 |
lambda 过于复杂 |
改用普通函数 |
在循环中创建 lambda |
注意闭包变量绑定问题 |
滥用 reduce |
优先考虑 sum、any、all 等内置函数 |
闭包陷阱示例(避免!)
python
# 错误:所有 lambda 共享同一个 i
funcs = []
for i in range(3):
funcs.append(lambda: i) # 所有返回 2!
# 正确:通过默认参数捕获当前值
funcs = []
for i in range(3):
funcs.append(lambda x=i: x)
9. 总结:何时使用函数式工具?
| 场景 | 推荐方式 |
|---|---|
| 简单数据转换 + 过滤 | ✅ 列表推导式 [x*2 for x in nums if x>0] |
| 已有命名函数应用 | ✅ map(my_func, data) |
| 复杂累积逻辑 | ⚠️ 谨慎使用 reduce,或用普通循环 |
| 需要惰性求值(大数据) | ✅ map/filter(返回迭代器) |
🐍 核心原则 :
"代码是写给人看的,其次才是机器。"选择最清晰、最易维护的写法,而非最"函数式"的写法。
下一步练习
- 用
map和filter重写你的 To-Do List 中的"筛选已完成任务"功能 - 编写一个函数,用
reduce计算列表中所有正数的乘积 - 对比以下三种写法的可读性:
map+filter- 列表推导式
- 普通
for循环
✨ 掌握函数式思维,不是为了炫技,而是多一种优雅表达逻辑的方式。
继续精进,写出既简洁又清晰的 Python 代码!

