title: 过滤 description: filter() 是 Python 的内置高阶函数,用于过滤序列中的元素。它接收一个函数和一个可迭代对象作为参数,返回一个迭代器(Python 3 中)包含所有使函数返回 True 的元素。

Python filter() 函数详解与实用案例

在 Python 函数式编程的工具箱里,filter() 是处理序列「筛选」场景的核心工具之一——它不会修改元素,只会根据规则精准保留或剔除,和 map() 是两个互补的常用高阶函数。

1. filter() 函数基础

核心定义

filter() 是 Python 内置的高阶函数,它接收两个参数:

  1. 判定函数:返回 True/False(或隐式转换为布尔值的对象,如空字符串、0、None 都是 False
  2. 可迭代对象:比如列表、元组、生成器、字符串等

Python 3 中,filter() 不会直接返回筛选后的序列,而是返回一个惰性迭代器——只有在真正遍历(如 next()for 循环、转成列表/元组)时才会计算结果,能大幅节省大数据集的内存。

基本语法

filter(function, iterable)

与 map() 的核心区别

我们用表格对比更直观:

高阶函数核心作用返回内容(Python 3)示例场景
map()批量转换每个元素转换后的迭代器数字平方、字符串转大写
filter()批量筛选符合条件的元素原元素组成的迭代器过滤奇数、过滤无效数据

2. 基础入门:两个简单场景

场景1:过滤列表中的奇数

这里先用显式的自定义函数写,方便理解判定逻辑:

def is_odd(n):
    return n % 2 == 1  # 余数为1 → 奇数 → 保留

numbers = [1, 2, 4, 5, 6, 9, 10, 15]
# 用 list() 把惰性迭代器转为可视化的列表
filtered_numbers = list(filter(is_odd, numbers))
print(filtered_numbers)  # 输出: [1, 5, 9, 15]

场景2:过滤无效字符串(空值、全空格)

处理爬虫或表单数据时,经常会遇到需要清理的空内容,filter() 处理起来很顺手:

def is_valid_str(s):
    # s.strip() 可以去掉首尾空格,如果结果是空 → s.strip() 是 False,整体返回 False → 剔除
    return s and s.strip()

raw_data = ['A', '', 'B', None, 'C', '   ', 'D']
valid_data = list(filter(is_valid_str, raw_data))
print(valid_data)  # 输出: ['A', 'B', 'C', 'D']

3. 进阶特性:惰性求值的魅力

为什么 Python 3 把 filter() 改成了返回迭代器?核心是内存优化——不需要一次性把所有符合条件的元素加载到内存里。

举个例子,我们可以逐步观察迭代器的执行过程:

# 第一步:定义 filter() 迭代器
# 此时函数 is_odd 还没有被调用过!
numbers = [3, 6, 2, 8, 10]
filtered = filter(lambda x: print(f"正在检查: {x}") or x > 5, numbers)

# 第二步:用 next() 逐步取元素
print("第一次取:", next(filtered))  # 输出「正在检查: 3」→ 跳过 → 继续「正在检查: 6」→ 取6
print("第二次取:", next(filtered))  # 跳过「正在检查: 2」→ 取8
print("第三次取:", next(filtered))  # 取10

# 第四步:再取的话会触发 StopIteration(迭代器耗尽)
# print(next(filtered))  # 取消注释会报错

4. 日常简化:结合 lambda 表达式

如果判定逻辑很简单(不需要复用),没必要单独写自定义函数,lambda + filter 是黄金组合:

# 过滤偶数
numbers = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)  # 输出: [2, 4, 6]

# 过滤长度≥5的单词
words = ["apple", "banana", "cat", "dog", "elephant"]
long_words = list(filter(lambda w: len(w) >= 5, words))
print(long_words)  # 输出: ['apple', 'banana', 'elephant']

5. 经典实用案例:埃拉托斯特尼筛法(生成无限素数)

这是 filter()无限生成器结合的绝佳例子——能高效地生成任意范围的素数,而且内存占用极低:

def infinite_primes():
    """生成无限素数的生成器"""
    # 第一步:生成从3开始的无限奇数序列(偶数除了2都不是素数,先排除)
    def _odd_iter():
        n = 1
        while True:
            n += 2
            yield n

    # 第二步:定义「是否不能被n整除」的判定函数
    def _not_divisible(n):
        return lambda x: x % n != 0

    # 先返回唯一的偶素数2
    yield 2
    # 初始化奇数生成器
    odd_seq = _odd_iter()
    while True:
        # 取当前奇数序列的第一个数 → 一定是素数
        current_prime = next(odd_seq)
        yield current_prime
        # 用 filter() 剔除能被 current_prime 整除的数 → 构造新的无限序列
        odd_seq = filter(_not_divisible(current_prime), odd_seq)

# 测试:打印100以内的素数
print("100以内的素数:")
for p in infinite_primes():
    if p < 100:
        print(p, end=' ')
    else:
        break
# 输出: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

6. 现代 Python 替代方案:列表/生成器表达式

虽然 filter() 很经典,但对于简单的、只需要一次结果的筛选列表推导式生成器表达式通常更易读(符合 Python 的「可读性优先」原则):

numbers = [3, 6, 2, 8]

# 方案1:filter() + lambda
result1 = list(filter(lambda x: x > 5, numbers))

# 方案2:列表推导式(更推荐给新手/简单场景)
result2 = [x for x in numbers if x > 5]

# 方案3:生成器表达式(等价于 filter() 的惰性特性,大数据集用)
result3 = (x for x in numbers if x > 5)

# 三个方案结果相同
print(result1, result2, list(result3))  # 输出: [6, 8] [6, 8] [6, 8]

7. 动手练习:筛选回文数

回文数是指正读反读都一样的数(如121、1331),我们可以用 filter() 快速实现:

def is_palindrome(n):
    """判断一个数是否是回文数"""
    s = str(n)
    return s == s[::-1]  # 切片 [::-1] 可以反转字符串

# 练习1:筛选1~1000的回文数
palindromes_1k = list(filter(is_palindrome, range(1, 1000)))
print("1~1000的回文数前15个:", palindromes_1k[:15])

# 练习2:简单验证(测试1~200的回文数是否符合预期)
test_data = range(1, 200)
expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 
            101, 111, 121, 131, 141, 151, 161, 171, 181, 191]
if list(filter(is_palindrome, test_data)) == expected:
    print("✅ 回文数筛选测试成功!")
else:
    print("❌ 回文数筛选测试失败!")

8. 性能与使用场景建议

性能对比

  • 内存效率filter() 和生成器表达式 > 列表推导式(后两者不需要预存所有结果)
  • 速度效率:三者在简单场景下差异极小,列表推导式可能略快(因为不需要额外的函数调用开销)

使用场景选择

场景推荐方案
简单筛选、结果需要多次使用列表推导式
复杂/复用的判定逻辑filter() + 自定义函数
大数据集、结果只需要遍历一次filter() 或生成器表达式

9. 总结

filter() 是 Python 函数式编程中不可或缺的筛选工具,但现代 Python 开发中不需要盲目使用——可读性永远是第一位的。

核心要点回顾:

  1. 接收「判定函数」和「可迭代对象」
  2. Python 3 返回惰性迭代器,内存友好
  3. 可以结合 lambda、自定义函数、无限生成器使用
  4. 简单场景优先考虑列表/生成器表达式

10. 扩展阅读

  • Python 官方文档:Built-in Functions — filter()
  • 补充过滤工具:itertools.filterfalse()(返回判定函数为 False 的元素)
  • 函数式编程三剑客:map()filter()functools.reduce()(Python 3 需导入)