查看全课大纲(第 30 / 51 节)
  1. 1.Python 是什么?为什么值得学?
  2. 2.如何为 Python 编程准备一个“全家桶”环境?
  3. 3.Python 有哪几种执行方法?
  4. 4.行与缩进到底有什么用?
  5. 5.注释有什么用,怎么写?
  6. 6.变量:如何给数据起个好名字?
  7. 7.运算符的优先级和常见坑点是什么?
  8. 8.Python 中,数字和布尔值究竟有哪几种?
  9. 9.输入函数 `input()` 和文件读取 `open()` 怎么用?
  10. 10.如何将程序的结果展示给用户或保存下来?
  11. 11.CSV 文件怎么读怎么写才方便?
  12. 12.列表是什么,如何创建和访问它?
  13. 13.列表的修改操作,有哪些方法?
  14. 14.列表切片为什么能取到部分元素?排序和查找又该怎么用?
  15. 15.判断语句:如何让程序根据条件做不同的事?
  16. 16.for 循环如何遍历序列中的元素?
  17. 17.while 循环什么时候才会停?
  18. 18.while 循环的结束条件,你写对了吗?
  19. 19.循环中途想提前结束,怎么办?
  20. 20.`break` 和 `continue` 到底有什么区别?
  21. 21.列表推导式如何让代码更简洁高效?
  22. 22.字符串怎么定义、拼接和操作?
  23. 23.元组:为什么定义单个元素时要加逗号?
  24. 24.集合(set)怎么用?如何快速去重和做集合运算?
  25. 25.字典是什么,为什么比列表更方便?
  26. 26.字典的增删改查与遍历,如何避免 KeyError?
  27. 27.函数里的变量,为什么有的能用有的不能用?
  28. 28.在函数内部修改全局变量,为什么有时不生效?
  29. 29.函数里能修改全局变量吗?返回值怎么用?
  30. 30.匿名函数:如何用 lambda 快速定义简单函数?
  31. 31.面向对象编程是什么,为什么需要它?
  32. 32.类中的方法和属性到底怎么定义和使用?
  33. 33.如何控制对对象内部属性和方法的访问?
  34. 34.异常发生时,程序会怎样继续执行?
  35. 35.如何组织代码:包和模块
  36. 36.`if __name__ == '__main__'` 到底有什么用?
  37. 37.如何用 IDE 的 Debug 功能排查程序错误?
  38. 38.Matplotlib 绘图的第一步该做什么?
  39. 39.Figure 是什么,如何设置图形尺寸?
  40. 40.如何自定义 Matplotlib 的坐标轴?
  41. 41.如何为图表添加图例,让不同曲线一目了然?
  42. 42.饼图怎么画才能直观展示数据占比?
  43. 43.如何用 Matplotlib 绘制散点图?
  44. 44.柱状图怎么画?
  45. 45.如何使用 Matplotlib 绘制等高线图?
  46. 46.如何在 Matplotlib 中绘制子图?
  47. 47.zip 函数如何把多个列表“打包”在一起?
  48. 48.如何给可迭代对象加上索引?
  49. 49.random 模块如何生成随机数?
  50. 50.math 模块怎么用?
  51. 51.Counter 如何快速统计元素出现次数?

匿名函数:如何用 lambda 快速定义简单函数?

约 8 分钟

小象实战讲义 · Python 编程从入门到实践

在上一节,我们学习了如何用 def 关键字定义有名字的函数。但有时,我们只需要一个简单的、只用一次的计算逻辑,为它单独命名和定义显得有些繁琐。这时,匿名函数(lambda 函数)就派上用场了。本节将学习 lambda 函数的定义、使用场景以及它与普通函数的区别。

💡 核心导读

  • 是什么:匿名函数是用 lambda 关键字定义的、没有名字的简单函数。
  • 怎么用:语法为 lambda 参数列表: 表达式,表达式的结果会自动返回。
  • 关键限制:匿名函数只能包含一个表达式,不能写复杂的语句块(如循环、多行逻辑)。
  • 典型场景:作为参数传递给其他函数(如 sort() 方法的 key 参数),实现简洁的回调逻辑。
  • 与普通函数的关系:功能上可以相互替代,但匿名函数更简洁,适用于简单、一次性的操作。

匿名函数的基本语法

匿名函数使用 lambda 关键字定义,其基本结构如下:

lambda 参数1, 参数2, ... : 表达式
  • lambda:定义匿名函数的关键字。
  • 参数列表:与普通函数类似,可以接收零个或多个参数,用逗号分隔。
  • ::冒号分隔参数列表和函数体。
  • 表达式:匿名函数的“函数体”。这个表达式会被计算,其结果自动作为函数的返回值。注意,这里不能使用 return 关键字,也不能编写多行代码或多个语句。

下面是一个最简单的例子,它定义了一个计算两数之和的匿名函数:

# 定义一个匿名函数,计算两个数的和,并将其赋值给变量 sum_func
sum_func = lambda x, y: x + y

# 通过变量名调用这个匿名函数
result = sum_func(10, 20)
print(result)  # 输出:30
30

虽然我们将匿名函数赋值给了变量 sum_func,但函数本身仍然是“匿名”的。sum_func 只是一个指向这个匿名函数的变量,我们可以像调用普通函数一样使用它。

匿名函数的典型使用场景

匿名函数最常见的用途是作为参数传递给另一个函数,这使得代码非常紧凑。

作为自定义函数的参数

假设我们有一个函数 xy_comp,它接收两个数字和一个函数作为参数,并用传入的函数对这两个数字进行计算。

# 定义一个函数,它接收两个数字和一个函数参数
def xy_comp(x, y, func):
    """使用传入的函数 func 计算 x 和 y"""
    return func(x, y)

# 场景1:传入一个计算加法的匿名函数
add_result = xy_comp(3, 5, lambda a, b: a + b)
print("3 + 5 = {}".format(add_result))

# 场景2:传入一个计算乘法的匿名函数
mul_result = xy_comp(3, 5, lambda a, b: a * b)
print("3 * 5 = {}".format(mul_result))
3 + 5 = 8
3 * 5 = 15

这里,我们分别传入了两个不同的匿名函数给 xy_comp,从而得到了加法和乘法的结果。如果不用匿名函数,我们需要先定义两个有名字的函数(如 def my_add(a, b): 和 def my_mul(a, b):),再传进去,代码会显得冗余。

作为内置函数的参数

Python 许多内置函数或方法支持接收函数作为参数,匿名函数在这里大放异彩。一个经典的例子是列表的 sort() 方法中的 key 参数。

假设我们有一个字典列表,需要根据字典中的某个值进行排序。

# 一个包含字典的列表
people = [
    {"name": "张三", "age": 25},
    {"name": "李四", "age": 30},
    {"name": "王五", "age": 20}
]

# 使用 sort() 方法,根据 'age' 字段进行升序排序
# key 参数接收一个函数,这个函数会应用于列表的每一个元素,并以其返回值作为排序依据
people.sort(key=lambda person: person["age"])
print("按年龄升序排序:")
for p in people:
    print(p)

print("\n" + "="*30 + "\n")

# 重新初始化列表,演示降序排序
people = [
    {"name": "张三", "age": 25},
    {"name": "李四", "age": 30},
    {"name": "王五", "age": 20}
]
# 使用 reverse=True 实现降序
people.sort(key=lambda p: p["age"], reverse=True)
print("按年龄降序排序:")
for p in people:
    print(p)
按年龄升序排序:
{'name': '王五', 'age': 20}
{'name': '张三', 'age': 25}
{'name': '李四', 'age': 30}

==============================

按年龄降序排序:
{'name': '李四', 'age': 30}
{'name': '张三', 'age': 25}
{'name': '王五', 'age': 20}

key=lambda p: p["age"] 这行代码非常清晰地表达了排序规则:“对于列表中的每个元素 p,取其 'age' 键对应的值来比较大小”。

匿名函数与普通函数的对比

匿名函数是普通函数的一种简洁写法,但并非全能替代。下表总结了它们的核心区别:

特性匿名函数 (lambda)普通函数 (def)
定义关键字lambdadef
函数名无(匿名)有
函数体只能是单个表达式可以是任意复杂的语句块
返回值表达式结果自动返回需要使用 return 语句显式返回
适用场景简单的、一次性的逻辑,常作为参数传递复杂的、需要复用的逻辑
可读性简单时非常简洁,复杂时降低可读性结构清晰,适合封装复杂逻辑

简单来说:如果你的函数逻辑简单到可以写成一个表达式,并且不需要在其他地方重复调用,那么使用 lambda 会让代码更简洁。否则,请使用 def 定义普通函数。

📝 动手练一练

  1. 改写练习:下面的普通函数功能是判断一个数字是否为偶数。请尝试将其改写为一个功能相同的匿名函数,并调用它检查数字 7 和 10。

    def is_even(n):
        return n % 2 == 0
👉 点击查看参考答案

思路:匿名函数需要一个参数 n,表达式为 n % 2 == 0。我们可以将其赋值给一个变量,然后调用。

# 将匿名函数赋值给变量 check_even
check_even = lambda n: n % 2 == 0

# 调用测试
print("7 是偶数吗? {}".format(check_even(7)))
print("10 是偶数吗? {}".format(check_even(10)))
7 是偶数吗? False
10 是偶数吗? True
  1. 排序应用:有一个字符串列表 ['apple', 'Banana', 'cherry', 'Date']。请使用列表的 sort() 方法和匿名函数,实现不区分大小写的字母顺序排序(即期望结果为 ['apple', 'Banana', 'cherry', 'Date'] 按 a, b, c, d 排序)。
👉 点击查看参考答案

思路:list.sort() 的 key 参数可以接收一个函数,对每个元素进行处理后再排序。要实现不区分大小写,可以将每个元素都转换为大写后再比较。

fruits = ['apple', 'Banana', 'cherry', 'Date']

# 使用匿名函数,将每个水果名转换为大写作为排序键
fruits.sort(key=lambda x: x.upper())
print(fruits)
['apple', 'Banana', 'cherry', 'Date']

常见错误

错误写法现象或报错原因正确写法
lambda x, y: return x + ySyntaxError: invalid syntax匿名函数体是表达式,其值自动返回,不能使用 return 语句。lambda x, y: x + y
f = lambda x: x*2 后直接 print(f),期望打印结果 8打印出的是函数对象,而不是计算结果 8f 是函数对象本身,打印它不会执行函数。需要调用函数才能得到结果。f = lambda x: x*2 后使用 print(f(4))
在复杂逻辑中坚持使用 lambda代码可读性急剧下降Lambda 适用于简单表达式。强行嵌套或编写复杂 lambda 会使代码难以理解和维护。此时应使用 def 定义普通函数。使用 def 定义多行、有名字的函数。

小结

  1. 匿名函数使用 lambda 关键字定义,格式为 lambda 参数: 表达式。
  2. 表达式的结果会自动成为函数的返回值,无需 return。
  3. 匿名函数的核心优势是简洁,特别适合作为参数传递给其他函数(如 sort(key=...))。
  4. 匿名函数只能包含一个表达式,不能编写多行语句或复杂逻辑,这是它与普通函数 (def) 的主要区别。
  5. 如果函数逻辑很简单且只用一次,用 lambda;如果需要复用或逻辑复杂,用 def。

📋 行动清单

  • 尝试将本节 xy_comp 函数的例子,改用 def 定义两个普通函数(add 和 mul)来实现,对比两种写法的代码长度和直观感受。
  • 找一个你之前写的列表,尝试用 sort(key=lambda ...) 的方式,根据元素的某个属性或计算后的值进行排序。
  • 把示例中的 sum_func 换成另一个变量名再调用一次,体会“匿名函数”只是没有名字,赋值后仍可通过变量调用。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 第3章代码包:函数(含1 个 Notebook)
    ZIP · 3KB
    下载