Python: 高阶函数与Lambda
Python 中函数也是一种"值",可以像数字、字符串一样赋值给变量、传给其他函数。利用这个特性,我们可以写出非常简洁、优雅的代码。高阶函数就是接收函数作为参数或返回函数的函数。这一课会让你打开新世界的大门。
1. 函数是一等公民
在 Python 中,函数可以像普通值一样操作:
▶ 示例:函数作为值传递
def say_hello(name):
return f"你好,{name}"
# 把函数赋值给变量
my_func = say_hello
print(my_func("Alice")) # 你好,Alice
# 函数可以作为参数传递
def greet_with(func, name):
return func(name)
print(greet_with(say_hello, "Bob")) # 你好,Bob
# 函数可以作为返回值
def create_greeter(greeting):
def greeter(name):
return f"{greeting},{name}!"
return greeter
say_hi = create_greeter("嗨")
say_hello = create_greeter("你好")
print(say_hi("Alice")) # 嗨,Alice!
print(say_hello("Bob")) # 你好,Bob!
输出:
# 函数定义成功
2. map():批量转换
map() 对序列中的每个元素执行同一个函数,返回一个新迭代器:
▶ 示例:map 批量转换
# 把列表中的每个数字平方
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # [1, 4, 9, 16, 25]
# 字符串列表转大写
fruits = ["apple", "banana", "cherry"]
upper_fruits = list(map(str.upper, fruits))
print(upper_fruits) # ['APPLE', 'BANANA', 'CHERRY']
# 摄氏转华氏
temps_c = [0, 10, 20, 30, 40]
temps_f = list(map(lambda c: c * 9 / 5 + 32, temps_c))
print(temps_f) # [32.0, 50.0, 68.0, 86.0, 104.0]
输出:
# 执行成功
map()等价于列表推导式:map(f, seq)≈[f(x) for x in seq]。选哪个主要看个人偏好——推导式更"Python 风格"。
3. filter():批量筛选
filter() 筛选出使函数返回 True 的元素:
▶ 示例:filter 筛选数据
# 筛选出偶数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6, 8, 10]
# 筛选出长度 >= 5 的单词
words = ["cat", "elephant", "dog", "giraffe", "ant"]
long_words = list(filter(lambda w: len(w) >= 5, words))
print(long_words) # ['elephant', 'giraffe']
# 筛选出非空字符串
data = ["hello", "", "world", "", "python"]
non_empty = list(filter(None, data)) # None 表示"去掉假值"
print(non_empty) # ['hello', 'world', 'python']
输出:
# 执行成功
filter()也等价于推导式:filter(f, seq)≈[x for x in seq if f(x)]。用 None 作为函数时,等价于去掉所有假值(""、0、None、False等)。
4. sorted() 高阶用法
第 11 课学了 sorted() 的 key 参数,这里更深入地看看:
▶ 示例:sorted 自定义排序
# 按对象的某个属性排序
students = [
{"name": "Alice", "score": 85},
{"name": "Bob", "score": 92},
{"name": "Charlie", "score": 78},
]
# 按分数降序
ranked = sorted(students, key=lambda s: s["score"], reverse=True)
for s in ranked:
print(f"{s['name']}: {s['score']}")
# 按名字长度排序
sorted_by_name = sorted(students, key=lambda s: len(s["name"]))
print([s["name"] for s in sorted_by_name]) # ['Alice', 'Charlie', 'Bob']
输出:
# 执行成功
▶ 示例:多级排序(难度⭐⭐)
# 先按分数降序,分数相同按名字字母顺序
data = [
("Alice", 85),
("Bob", 92),
("Charlie", 85),
("赵六", 92),
]
def sort_key(item):
# 返回元组:先按分数降序(负数 = 反序),再按名字
return (-item[1], item[0])
sorted_data = sorted(data, key=sort_key)
for name, score in sorted_data:
print(f"{name}: {score}")
运行结果:
Bob: 92
赵六: 92
Charlie: 85
Alice: 85
5. reduce():累积计算
reduce() 把序列中的元素累积起来,每次用函数处理两个元素。它不在内置函数中,需要从 functools 导入:
▶ 示例:reduce 累积计算
from functools import reduce
# 计算所有数字的乘积
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print(product) # 120(1×2×3×4×5)
# 找最大值
max_val = reduce(lambda a, b: a if a > b else b, [3, 1, 4, 1, 5])
print(max_val) # 5
# 拼接字符串
words = ["Hello", " ", "World", " ", "Python"]
sentence = reduce(lambda a, b: a + b, words)
print(sentence) # Hello World Python
输出:
# 执行成功
(1) reduce() 的执行过程
# reduce(lambda x, y: x + y, [1, 2, 3, 4])
# 第1步:x=1, y=2 → 3
# 第2步:x=3, y=3 → 6
# 第3步:x=6, y=4 → 10
# 结果:10
reduce() vs 循环: 任何 reduce() 能做的事,for 循环也能做。reduce() 的优点是代码更简洁、更"声明式"——你在说"我要做什么"而不是"我要怎么做"。缺点是初次接触的人可能看不懂。
6. Lambda 表达式深入
Lambda 的名字来自 λ(希腊字母),本质就是匿名函数——没有名字、用完就扔的小函数。
(1) Lambda vs 普通函数
▶ 示例:Lambda 对比普通函数
# 普通函数
def double(x):
return x * 2
# Lambda 表达式
double = lambda x: x * 2
print(double(5)) # 10
输出:
# 函数定义成功
(2) Lambda 的完整语法
lambda 参数: 表达式
# ↑ 等价于
def 匿名函数(参数):
return 表达式
(3) 多个参数
▶ 示例:Lambda 多个参数
add = lambda a, b: a + b
print(add(3, 5)) # 8
# 三元表达式在 lambda 中
max_val = lambda a, b: a if a > b else b
print(max_val(10, 20)) # 20
输出:
# 执行成功
(4) 什么时候用 Lambda
▶ 示例:Lambda 适用场景
# ✅ 适合:简单的一行变换,作为高阶函数的参数
numbers = [1, 2, 3, 4]
result = list(map(lambda x: x ** 2, numbers))
# ❌ 不适合:逻辑复杂,需要多行
# 这种应该写成普通 def 函数
输出:
# 函数定义成功
7. 常见应用场景
- 数据管道:
map()→filter()→sorted()组合处理数据。 - 自定义排序:用
lambda做key参数实现各种排序规则。 - 事件回调:用函数作为参数传给 GUI 或 Web 框架。
- 闭包工厂:外层函数返回内层函数,实现"参数化"功能(像上面的
create_greeter)。 - 惰性计算:用高阶函数延迟求值,只在需要时才计算结果。
❓ 常见问题
map() 和列表推导式哪个更好?map() 的优势是:① 当你有现成的函数名时更短(map(str.upper, seq) vs [s.upper() for s in seq]);② 返回的是惰性迭代器,大数据量时省内存。多数场景下,列表推导式是更好的选择。reduce() 在现代 Python 中还用吗?reduce(),认为它太难理解。大多数 reduce() 的场景可以用循环替代,或者有更直接的函数(如 sum()、max())。不过在函数式编程中,reduce() 仍然是一个重要的概念。📖 小节
- Python 中函数是一等公民——可以赋值、传参、返回
map(f, seq)对每个元素执行函数,list()转为列表filter(f, seq)筛选使函数返回 True 的元素sorted(seq, key=f)的 key 参数接受函数,实现自定义排序reduce(f, seq)累积计算,需要从functools导入- Lambda
lambda 参数: 表达式是匿名单行函数,适合简单场景
📝 作业
-
基础题(难度⭐):给定列表
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],用map()和filter()分别实现:筛选出奇数并计算它们的平方。提示:先用filter筛奇数,再用map平方。 -
进阶题(难度⭐⭐):给定字典列表
products = [{"name": "A", "price": 100}, {"name": "B", "price": 80}, {"name": "C", "price": 120}],用sorted()按价格降序排序,并输出名称和价格。 -
挑战题(难度⭐⭐⭐):用
reduce()实现flatten(nested_list)函数,把嵌套列表"展平"一层。例如flatten([[1, 2], [3, 4], [5]])返回[1, 2, 3, 4, 5]。提示:reduce中每次用+合并两个列表。完成后用列表推导式实现同样的功能,比较两种写法的差异。