← 返回题目列表

Python 中 lambda 和 def 有什么区别?

高频 简单 第 2 / 21 题 更新于 2026/07/27
lambdadef匿名函数函数表达式

简化版

lambda 用来创建匿名小函数,只能写单个表达式;def 用来定义普通函数,可以包含多条语句、文档字符串、注解和复杂逻辑。面试中要强调:lambda 适合短小回调,不适合承载复杂业务逻辑。

详细版

示例:

square = lambda x: x * x

等价于:

def square(x):
    return x * x

主要区别:

对比点lambdadef
名称通常匿名,也可赋给变量有函数名
函数体只能是一个表达式可以是多条语句
返回值表达式结果自动返回使用 return 返回
可读性适合短逻辑适合复杂逻辑
文档和注解不适合写完整说明支持文档字符串和注解

常见使用:

users = [{"name": "Tom", "age": 18}, {"name": "Jerry", "age": 16}]
users.sort(key=lambda user: user["age"])

如果逻辑变复杂,就应该改成 def

def user_sort_key(user):
    return user["age"]

完整版教学

一、lambda 是表达式,不是语句块

lambda 的语法:

lambda 参数列表: 表达式

例如:

add = lambda a, b: a + b

冒号后面必须是表达式,表达式会自动作为返回值。

你不能在 lambda 里写多条语句:

# 错误示意
lambda x: y = x + 1

也不适合写复杂分支、循环、异常处理。虽然可以写条件表达式:

label = lambda score: "pass" if score >= 60 else "fail"

但如果逻辑继续变复杂,可读性会迅速变差。

二、def 更适合表达业务含义

def 定义的函数可以有函数名、文档字符串、类型注解和多条语句:

def normalize_name(name: str) -> str:
    """去掉首尾空格,并统一为小写。"""
    return name.strip().lower()

函数名本身就是文档。看到 normalize_name,读者能大致知道它做什么;看到一长串 lambda,读者需要解析表达式才能理解。

工程代码里,可读性通常比少写几行更重要。

三、lambda 常见使用场景

lambda 适合传给高阶函数,作为一次性的小逻辑。

排序:

students = [
    {"name": "Tom", "score": 80},
    {"name": "Jerry", "score": 95},
]

students.sort(key=lambda s: s["score"])

映射:

nums = [1, 2, 3]
result = list(map(lambda x: x * 2, nums))

过滤:

evens = list(filter(lambda x: x % 2 == 0, nums))

不过在 Python 中,列表推导式通常比 map + lambda 更直观:

result = [x * 2 for x in nums]
evens = [x for x in nums if x % 2 == 0]

四、lambda 和闭包的关系

lambda 也会遵守作用域和闭包规则。

def make_adder(n):
    return lambda x: x + n

add_10 = make_adder(10)
print(add_10(5))  # 15

它也会遇到延迟绑定问题:

funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])  # [2, 2, 2]

修复:

funcs = [lambda i=i: i for i in range(3)]

所以 lambda 不是特殊作用域,它只是创建函数对象的简短语法。

五、不要为了炫技滥用 lambda

不推荐写:

process = lambda users: list(map(lambda u: u["name"].strip().lower(), filter(lambda u: u["active"], users)))

更清晰的写法:

def active_user_names(users):
    names = []
    for user in users:
        if user["active"]:
            names.append(user["name"].strip().lower())
    return names

代码给机器执行,也给人维护。lambda 用得好是简洁,用过头就是阅读障碍。

六、常见误区与追问

记忆钩子:lambda 解决的是“把一个短表达式当函数传出去”,不是解决“少写 def”。一旦需要命名意图、调试定位或多步逻辑,就该回到 def

  • 误区:lambda 比 def 性能更高。 二者都会创建函数对象,主要差异在语法表达能力和可读性,不应把 lambda 当作性能优化手段。
  • 误区:lambda 不能有参数默认值。 lambda x, step=2: x + step 是合法的;循环闭包里也常用 lambda i=i: i 固定当前循环值。
  • 追问:lambda 为什么不能写赋值语句和 for 循环语句? Python 语法规定 lambda 冒号后必须是单个表达式;赋值、fortry 这类语句块需要用 def 承载。
  • 追问:lambda 赋给变量后还是匿名函数吗? 函数对象本身的 __name__ 仍通常是 '<lambda>',变量名只是外部绑定;调试日志里看到 <lambda> 往往不如具名函数清楚。
  • 误区:map/filter + lambda 一定更 Pythonic。 在很多场景下,列表推导式或生成器表达式更直接,例如 [x * 2 for x in nums]list(map(lambda x: x * 2, nums)) 更容易读。
  • 追问:lambda 和闭包有什么关系? lambdadef 一样遵守 LEGB 与延迟绑定规则;循环里创建 lambda 时,如果引用循环变量,调用时读到的可能是循环结束后的最终值。

七、加强记忆

lambda 是“单表达式匿名函数”,def 是“完整函数定义”。短小、一次性的 key 函数或回调用 lambda 很合适;只要逻辑需要命名、注释、分支、异常处理或复用,就果断用 def。面试时别只说语法差异,要补一句可读性和维护性取舍。