本章摘要

  1. 核心目标:掌握 lambdamap/filter/sorted,用简洁代码完成批量数据处理
  2. 核心知识点:lambda 语法、map() 映射、filter() 过滤、sorted() 排序及 key 参数
  3. 实操产出:计算器(lambda 四则运算)+ 密码强度校验(高阶函数批量处理)
  4. 前置基础:第10章函数进阶(参数、返回值、作用域)、第4章循环、第6章列表

一、写在前面

上一章你学了函数进阶——默认参数、可变参数 *args/**kwargs、返回值、变量作用域。现在你已经能写出结构清晰的函数了。

但你有没有遇到过这种情况:某个函数特别简单,比如"把一个数乘以 2",你只想用它一次,却还得 def 起个名字、写两行代码。这就好比你只想喝口水,却非要正式地摆好茶具——太重了。

Python 提供了一个更轻量的方案:lambda 匿名函数。一行搞定,不用起名字,用完即走。围绕着 lambda,Python 还内置了三个高阶函数——map()filter()sorted(),它们能把"对数据批量操作"这件事做到极致简洁。

本章就来一次性拿下这四个工具。学完之后,你处理列表数据的能力会有质的飞跃。


二、什么是高阶函数

在讲具体工具之前,先搞清楚一个概念:高阶函数

高阶函数就是接收函数作为参数,或者返回一个函数的函数。说白了,函数不再只是被调用的"打工人",它还可以被当作"数据"传来传去。

# 你已经熟悉的普通函数调用
print(len("hello"))   # len 是函数,"hello" 是数据

# 高阶函数:把函数当作参数传给另一个函数
numbers = [1, 2, 3, 4, 5]

# map 接收了一个函数(lambda)作为参数
result = list(map(lambda x: x ** 2, numbers))
print(result)   # [1, 4, 9, 16, 25]

你看,map() 接收的第一个参数不是数字、不是字符串,而是一个函数。这就是高阶函数的核心特征。

在这里插入图片描述

Python 内置的高阶函数不止三个,但最常用的就是 map()filter()sorted()。它们三个配合 lambda,能覆盖大部分"批量处理数据"的场景。下面逐个击破。


三、lambda 匿名函数

3.1 lambda 是什么

lambda 是一行搞定的匿名函数。不需要 def,不需要 return,写完就能用。

语法非常简单:

lambda 参数: 表达式
  • lambda 是关键字
  • 冒号左边是参数(可以没有,可以多个)
  • 冒号右边是返回值(只能写一个表达式,不能写多行语句)
# 用 def 写一个加法函数
def add(x, y):
    return x + y

# 用 lambda 写同样的加法
add_lambda = lambda x, y: x + y

print(add(3, 5))          # 8
print(add_lambda(3, 5))   # 8

两种写法效果一模一样,但 lambda 只用了一行。

在这里插入图片描述

3.2 lambda 的参数玩法

lambda 的参数规则和普通函数完全一样——可以有多个参数,可以有默认值:

# 无参数
greet = lambda: "你好!"
print(greet())   # 你好!

# 一个参数
square = lambda x: x ** 2
print(square(5))   # 25

# 多个参数
add = lambda x, y: x + y
print(add(3, 7))   # 10

# 带默认值
power = lambda x, n=2: x ** n
print(power(3))       # 9(默认平方)
print(power(3, 3))    # 27(指定立方)

3.3 lambda vs def:什么时候用哪个

对比项deflambda
行数多行,可写复杂逻辑一行,只能一个表达式
函数名必须有名字匿名,不需要起名
返回值return 返回表达式结果自动返回
可读性逻辑清晰,适合复用简洁,适合一次性使用
适用场景复杂逻辑、需要复用简单操作、作为参数传递

一句话原则: 逻辑简单(一行能写完)且只用一次,用 lambda;逻辑复杂或需要多处复用,用 def

# ✅ 适合 lambda:简单的数学运算,作为参数传给 sorted
students = [{"name": "小明", "score": 85}, {"name": "小红", "score": 92}]
ranked = sorted(students, key=lambda s: s["score"])

# ❌ 不适合 lambda:多步骤逻辑,强行写成 lambda 会很难读
# 下面这行能运行,但没人看得懂,不如用 def
# process = lambda data: [x ** 2 for x in data if x > 0]  # 能看懂但何必呢

新手建议:刚开始学,遇到拿不准的情况就用 deflambda 用熟了自然知道什么时候该用。


四、map() 映射:批量处理利器

4.1 map() 做什么

map() 的作用是:对一个可迭代对象中的每个元素,都套用同一个函数,然后返回结果。

语法:

map(函数, 可迭代对象)

比如你有一个字符串列表 ["1", "2", "3"],想把每个都转成整数,一个个写循环太麻烦,map 一行搞定:

str_nums = ["1", "2", "3", "4", "5"]

# map 把 int 函数套用到每个元素上
result = list(map(int, str_nums))
print(result)   # [1, 2, 3, 4, 5]

注意:map() 返回的是 map 对象(迭代器),不是列表。需要用 list() 转换才能看到内容。这是新手最容易忽略的地方。

4.2 map() 配合 lambda

map() 最常见的用法是配合 lambda,自定义变换规则:

# 把一组摄氏温度转华氏温度:F = C * 1.8 + 32
celsius = [0, 10, 20, 30, 40]
fahrenheit = list(map(lambda c: c * 1.8 + 32, celsius))
print(fahrenheit)   # [32.0, 50.0, 68.0, 86.0, 104.0]

# 把一组数字全部翻倍
numbers = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, numbers))
print(doubled)   # [2, 4, 6, 8, 10]

# 把一组名字全部转大写
names = ["alice", "bob", "charlie"]
upper_names = list(map(str.upper, names))
print(upper_names)   # ['ALICE', 'BOB', 'CHARLIE']

第三个例子直接传了 str.upper 方法名,省去了 lambda,更简洁。

4.3 map() 处理多个可迭代对象

map() 可以同时接收多个可迭代对象,函数的参数个数要对应:

# 两个列表对应位置相加
prices = [10, 20, 30]
quantities = [2, 3, 1]

# lambda 接收两个参数,分别来自两个列表
totals = list(map(lambda p, q: p * q, prices, quantities))
print(totals)   # [20, 60, 30]

如果两个列表长度不同,map 会以最短的为准,多出来的元素自动忽略。

4.4 map() vs for 循环

同样的功能,用 for 循环也能写,但 map 更简洁:

# for 循环写法
numbers = [1, 2, 3, 4, 5]
squared = []
for n in numbers:
    squared.append(n ** 2)

# map 写法(一行搞定)
squared = list(map(lambda x: x ** 2, numbers))

不是说要抛弃 for 循环,而是在"对每个元素做同样变换"的场景下,map 更直观、更省代码。


五、filter() 过滤:按条件筛选

5.1 filter() 做什么

filter() 的作用是:按照条件筛选元素,留下满足条件的,丢掉不满足的。

语法:

filter(函数, 可迭代对象)

传入的函数必须返回 TrueFalse。返回 True 的元素保留,返回 False 的丢弃。

# 筛选列表中的偶数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

def is_even(n):
    return n % 2 == 0

evens = list(filter(is_even, numbers))
print(evens)   # [2, 4, 6, 8, 10]

5.2 filter() 配合 lambda

map 一样,filter 最常见的搭档也是 lambda

# 筛选偶数(lambda 版)
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]

# 筛选长度大于 3 的字符串
words = ["hi", "hello", "ok", "python", "go"]
long_words = list(filter(lambda w: len(w) > 3, words))
print(long_words)   # ['hello', 'python']

# 筛选及格成绩(≥60)
scores = [45, 78, 90, 56, 61, 33, 88]
passed = list(filter(lambda s: s >= 60, scores))
print(passed)   # [78, 90, 61, 88]

5.3 filter() 的返回值

map 一样,filter() 返回的也是迭代器对象,需要用 list() 转换:

result = filter(lambda x: x > 5, [1, 6, 3, 8, 2, 9])
print(result)        # <filter object at 0x...>
print(list(result))  # [6, 8, 9]

如果筛选后没有匹配的元素,结果就是空列表 [],不会报错。

5.4 map vs filter:别搞混

对比map()filter()
作用变换每个元素筛选元素
函数返回值任意值(变换后的结果)True / False
元素数量输入几个,输出几个输出 ≤ 输入(被过滤掉的不要)
类比给每个人发一顶帽子只让戴帽子的人进去

一句话区分:map 是"全都变",filter 是"挑着留"。


六、sorted() 排序:自定义排序规则

6.1 sorted() 基本用法

sorted() 的作用是:对可迭代对象排序,返回一个新的排好序的列表。

# 数字排序
scores = [78, 92, 56, 88, 65]
print(sorted(scores))           # [56, 65, 78, 88, 92]  升序
print(sorted(scores, reverse=True))  # [92, 88, 78, 65, 56]  降序

# 字符串排序(按字母顺序)
names = ["charlie", "alice", "bob"]
print(sorted(names))   # ['alice', 'bob', 'charlie']

sorted() 返回新列表,不修改原数据。如果想原地排序,用 列表.sort(),但这会改变原列表。

6.2 key 参数:自定义排序规则

这是 sorted() 最强大的功能。key 参数接收一个函数,函数作用于每个元素,排序时按函数的返回值来比较,但最终输出的还是原始元素。

# 按绝对值排序(不看正负,只看大小)
numbers = [-5, 3, -1, 8, -2]
print(sorted(numbers, key=abs))
# [−1, −2, 3, −5, 8]  → 按 |−1|, |−2|, |3|, |−5|, |8| 排列
# 按字符串长度排序
words = ["banana", "apple", "kiwi", "strawberry"]
print(sorted(words, key=len))
# ['kiwi', 'apple', 'banana', 'strawberry']

6.3 sorted() 配合 lambda

key 参数最常搭配 lambda 使用,灵活定义排序依据:

# 按成绩从高到低排序学生
students = [
    {"name": "小明", "score": 85},
    {"name": "小红", "score": 92},
    {"name": "小刚", "score": 78},
    {"name": "小美", "score": 96},
]

# lambda 取出每个学生的 score 作为排序依据
ranked = sorted(students, key=lambda s: s["score"], reverse=True)

for s in ranked:
    print(f"{s['name']}{s['score']}分")

运行结果:

小美:96分
小红:92分
小明:85分
小刚:78分

没有 key 参数,sorted() 不知道怎么比较字典,会直接报错(后面报错速查表会讲)。

6.4 多条件排序

key 函数可以返回元组,sorted() 会按元组的元素依次比较——先比第一个,相同再比第二个:

# 先按成绩降序,成绩相同再按姓名升序
students = [
    {"name": "小明", "score": 85},
    {"name": "小刚", "score": 85},
    {"name": "小红", "score": 92},
    {"name": "小美", "score": 96},
]

# 成绩取负数实现降序,姓名正序
ranked = sorted(students, key=lambda s: (-s["score"], s["name"]))

for s in ranked:
    print(f"{s['name']}{s['score']}分")

运行结果:

小美:96分
小红:92分
小刚:85分
小明:85分

小刚和小明都是 85 分,按姓名拼音排,"小刚"在"小明"前面。多条件排序在实际开发中非常常用。


七、lambda + 高阶函数组合使用

7.1 map + filter 链式调用

实际开发中,经常需要"先筛选,再变换"。filtermap 可以串联使用:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 第一步:filter 筛选偶数
evens = list(filter(lambda x: x % 2 == 0, numbers))
# 第二步:map 把偶数平方
squares = list(map(lambda x: x ** 2, evens))

print(squares)   # [4, 16, 36, 64, 100]

也可以一步到位,把 filter 的结果直接传给 map

# 嵌套写法:一步搞定
result = list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, numbers)))
print(result)   # [4, 16, 36, 64, 100]

嵌套写法虽然简洁,但可读性不如分步写。建议新手先写分步版,熟练后再用嵌套。

7.2 四个工具速查表

工具作用语法返回值是否改原数据
lambda创建匿名函数lambda 参数: 表达式函数对象不涉及
map()对每个元素变换map(函数, 可迭代对象)map 对象
filter()按条件筛选filter(函数, 可迭代对象)filter 对象
sorted()排序sorted(可迭代对象, key=函数, reverse=bool)新列表

四个工具都不修改原始数据,安全放心。


八、Scratch 积木对照

本章的 lambda 匿名函数、map/filter/sorted 高阶函数属于 Python 进阶特性,Scratch 中没有对应的积木。

原因很简单:Scratch 的积木是图形化、命名的,每个积木块都有明确的名字和形状。而 lambda 的核心就是"匿名"——连名字都不要,Scratch 的设计模型里根本没有这个概念。高阶函数"把函数当参数传给另一个函数"更是 Scratch 编程模型中不存在的操作。

这些知识点没有捷径,多写几遍代码就熟了。好在语法都很简洁,下面综合实战会一次性把它们串起来用。


九、综合实战:封装计算器 + 密码校验工具

本案例为第三部分(函数篇)毕业案例,综合运用第 9-11 章所学:函数定义、参数传递、返回值、作用域、lambdamap/filter/sorted

案例说明

我们要写两个工具:

  1. 计算器函数:支持加减乘除,用 lambda 实现运算逻辑
  2. 密码强度校验函数:判断密码强度(长度、是否含数字、是否含特殊字符)

然后用 map/filter/sorted 对一批密码做批量校验和排名。

完整源码

# ========================================
# 综合实战:封装计算器 + 密码校验工具
# 第三部分(函数篇)毕业案例
# ========================================

# ---------- Part 1:计算器(lambda 实现四则运算) ----------

def calculator(a, b, operator):
    """计算器函数:用 lambda 实现四则运算"""
    # 用字典存储运算符到 lambda 的映射
    operations = {
        "+": lambda x, y: x + y,
        "-": lambda x, y: x - y,
        "*": lambda x, y: x * y,
        "/": lambda x, y: x / y if y != 0 else "错误:除数不能为0",
    }

    if operator not in operations:
        return f"不支持的操作符:{operator}"

    return operations[operator](a, b)


# 测试计算器
print("===== 计算器测试 =====")
print(f"10 + 3 = {calculator(10, 3, '+')}")
print(f"10 - 3 = {calculator(10, 3, '-')}")
print(f"10 * 3 = {calculator(10, 3, '*')}")
print(f"10 / 3 = {calculator(10, 3, '/')}")
print(f"10 / 0 = {calculator(10, 0, '/')}")
print(f"10 % 3 = {calculator(10, 3, '%')}")


# ---------- Part 2:密码强度校验 ----------

def has_digit(text):
    """检查字符串中是否包含数字"""
    for char in text:
        if char.isdigit():
            return True
    return False


def has_special(text):
    """检查字符串中是否包含特殊字符"""
    specials = "!@#$%^&*()-_=+"
    for char in text:
        if char in specials:
            return True
    return False


def check_password(password):
    """检查密码强度,返回包含详细信息的字典"""
    # 用 lambda 和已有函数定义校验规则
    rules = [
        ("长度≥8位", lambda p: len(p) >= 8),
        ("包含数字", has_digit),
        ("包含特殊字符", has_special),
    ]

    passed = []
    for rule_name, check_func in rules:
        if check_func(password):
            passed.append(rule_name)

    score = len(passed)
    if score == 3:
        strength = "强"
    elif score == 2:
        strength = "中"
    else:
        strength = "弱"

    return {
        "password": password,
        "strength": strength,
        "score": score,
        "passed": passed,
    }


# 测试单个密码
print("\n===== 密码校验测试 =====")
result = check_password("P@ssw0rd!")
print(f"密码:{result['password']}")
print(f"强度:{result['strength']}{result['score']}/3)")
print(f"通过:{result['passed']}")


# ---------- Part 3:批量处理(map + filter + sorted) ----------

print("\n===== 批量密码校验 =====")

# 一批待检查的密码
passwords = ["123", "abc12345", "P@ssw0rd!", "hello", "MyP@ss2024"]

# map():批量校验所有密码
results = list(map(check_password, passwords))

# filter():筛选弱密码(score ≤ 1)
weak_passwords = list(filter(lambda r: r["score"] <= 1, results))

# sorted():按强度分数从低到高排序
ranked = sorted(results, key=lambda r: r["score"])

print("密码强度排名(从弱到强):")
for r in ranked:
    print(f"  {r['password']:<12} 强度:{r['strength']}  通过:{r['passed']}")

print(f"\n⚠️ 检测到 {len(weak_passwords)} 个弱密码,建议立即修改!")
for w in weak_passwords:
    print(f"  ❌ {w['password']}")

运行结果:

===== 计算器测试 =====
10 + 3 = 13
10 - 3 = 7
10 * 3 = 30
10 / 3 = 3.3333333333333335
10 / 0 = 错误:除数不能为0
10 % 3 = 不支持的操作符:%

===== 密码校验测试 =====
密码:P@ssw0rd!
强度:强(3/3)
通过:['长度≥8位', '包含数字', '包含特殊字符']

===== 批量密码校验 =====
密码强度排名(从弱到强):
  123          强度:弱  通过:['包含数字']
  hello        强度:弱  通过:[]
  abc12345     强度:中  通过:['长度≥8位', '包含数字']
  P@ssw0rd!    强度:强  通过:['长度≥8位', '包含数字', '包含特殊字符']
  MyP@ss2024   强度:强  通过:['长度≥8位', '包含数字', '包含特殊字符']

⚠️ 检测到 2 个弱密码,建议立即修改!
  ❌ 123
  ❌ hello

分步拆解

Part 1 — 计算器函数 calculator

  1. 字典 + lambda 存储运算逻辑:用字典把运算符映射到对应的 lambda 函数。"+" 对应 lambda x, y: x + y,调用时直接 operations[operator](a, b) 就能执行运算。这比写一堆 if-else 优雅得多。
  2. 除零保护:除法 lambda 中用条件表达式 x / y if y != 0 else "错误:除数不能为0",避免程序崩溃。
  3. 非法操作符处理:先检查 operator not in operations,不支持的运算符返回提示信息,而不是报错。

Part 2 — 密码强度校验 check_password

  1. 辅助函数 has_digit / has_special:这两个函数逻辑稍复杂(需要遍历字符),用 def 定义更清晰。它们的参数和返回值都很明确——接收字符串,返回布尔值。
  2. rules 列表存储校验规则:每条规则是一个元组 (规则名, 检查函数)。长度检查用 lambda(简单一行),数字和特殊字符检查用已有的 def 函数。这体现了"什么时候用 lambda,什么时候用 def"的实际判断。
  3. 遍历规则逐条检查for 循环遍历 rules,调用每个检查函数,通过的规则记入 passed 列表。check_func 就是被当作参数传递的函数——这就是高阶函数的思路。
  4. 返回字典:返回包含密码、强度、分数、通过项的字典。调用者可以按需取用任意字段。

Part 3 — 批量处理(高阶函数三连)

  1. map() 批量校验map(check_password, passwords)check_password 函数套用到每个密码上,一行代码完成五个密码的校验。
  2. filter() 筛选弱密码filter(lambda r: r["score"] <= 1, results) 从结果中筛出弱密码。这里 lambda 作为筛选条件,简洁明了。
  3. sorted() 排序sorted(results, key=lambda r: r["score"]) 按强度分数排序, weakest 排最前面,一目了然。

整个案例从函数定义到批量处理,串联了第 9-11 章的全部核心知识点。你可以把密码列表换成自己的密码试试看强度如何。


十、常见报错速查表

报错信息出现场景原因解决方法
TypeError: <lambda>() missing 1 required positional argument调用 lambda传参个数不够,如 lambda x, y: x+y 只传了一个参数确保参数个数与 lambda 定义一致
TypeError: 'map' object is not subscriptable访问 map 结果直接用 map_result[0] 取值list(map_result) 转成列表再索引
TypeError: 'filter' object is not subscriptable访问 filter 结果直接用 filter_result[0] 取值list(filter_result) 转成列表再索引
TypeError: 'NoneType' object is not callablemap/filter 传参第一个参数传了 None 或忘传函数确保第一个参数是可调用的函数
TypeError: '<' not supported between instances of 'dict' and 'dict'sorted 排序字典没加 key 参数,sorted 不知道怎么比较字典添加 key=lambda s: s["字段名"]
ZeroDivisionError: division by zerolambda 除法除法运算中除数为 0加条件判断:x / y if y != 0 else "错误"


十一、本章小结

本章你掌握了 Python 匿名函数与三大高阶函数:

  1. lambda 匿名函数——lambda 参数: 表达式,一行搞定简单函数,适合一次性使用和作为参数传递
  2. map() 映射——map(函数, 可迭代对象),对每个元素做变换,返回 map 对象需 list() 转换
  3. filter() 过滤——filter(函数, 可迭代对象),按条件筛选元素,函数返回 True 保留、False 丢弃
  4. sorted() 排序——sorted(可迭代对象, key=函数, reverse=bool),key 参数自定义排序规则,可配合 lambda 灵活排序
  5. 组合使用——map + filter 链式调用,sorted 多条件排序,四个工具搭配处理数据事半功倍

这四个工具是 Python 函数式编程的入门钥匙。当你发现自己写了大量"遍历 + 变换 + 筛选"的 for 循环时,想想能不能用 map/filter/sorted 替代,代码会简洁很多。

往期回顾:

《Python 零基础入门:从积木到代码》专栏序

零基础学 Python 第1章 | 全平台装环境 + VS Code 配置 + 第一个 Hello World

零基础学 Python 第2章 | print 输出 + 变量赋值 + input 交互输入

零基础学 Python 第3章 | 条件判断:if / elif / else

零基础学 Python 第 4 章 | for 循环与 range():让程序帮你重复干活

零基础学 Python 第 5 章 | while 循环与循环嵌套:让程序看着条件自己干活

零基础学 Python 第 6 章 | 元组与集合:不可变数据与自动去重

零基础学 Python 第7章 | 字典 dict:键值对存储

零基础学 Python 第8章 | 字符串操作与格式化输出

零基础学 Python 第9章 | 函数基础:def、参数与返回值

零基础学 Python 第10章 | 函数进阶:参数灵活用法与作用域

下一章预告:到目前为止,你的程序运行完数据就消失了——关掉终端,所有变量、列表、字典都不见了。下一章学习文件读写,让数据真正"存"下来,程序重启还能读回来。


文末资源区

资源说明
Python 官方文档 - lambdahttps://docs.python.org/3/tutorial/controlflow.html#lambda-expressions
Python 官方文档 - map()https://docs.python.org/3/library/functions.html#map
Python 官方文档 - filter()https://docs.python.org/3/library/functions.html#filter
Python 官方文档 - sorted()https://docs.python.org/3/library/functions.html#sorted
本章完整源码chapter11_all.py(关注梅雅达编程笔记,评论领资料)

每节课都配套课后练习题与完整源码。代码报错、看不懂知识点,可在评论区粘贴问题,逐一解答!
欢迎关注梅雅达编程笔记,持续分享Python零基础学习内容

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐