Python高级特性:filter() 函数完全指南
优雅地过滤序列元素
前言
filter() 是 Python 的内置高阶函数,用于过滤序列中的元素。它接收一个判断函数和一个可迭代对象,返回一个包含所有使函数返回 True 的元素的迭代器。与 map() 不同,filter() 的核心作用是筛选而非转换。
本文将系统讲解 filter() 的语法、惰性求值特性、与列表推导式的对比、以及素数筛选、回文数检测等实用案例,帮助你掌握这一函数式编程利器。
📚 本文内容基于:道满PythonAI - filter() 函数详解与实用案例

一、filter() 函数基础
1.1 基本语法
filter(function, iterable)
| 参数 | 说明 |
|---|---|
function | 判断函数,接收一个参数,返回布尔值(True/False) |
iterable | 可迭代对象(列表、元组、字符串等) |
| 返回值 | 迭代器(Python 3),包含所有使函数返回 True 的元素 |
1.2 filter() 与 map() 的区别
| 函数 | 作用 | 返回结果 |
|---|---|---|
map() | 将函数应用于每个元素 | 函数处理后的新值 |
filter() | 根据条件筛选元素 | 原序列中符合条件的元素 |
numbers = [1, 2, 3, 4, 5]
# map: 每个元素都转换
squared = list(map(lambda x: x**2, numbers))
print(squared) # [1, 4, 9, 16, 25]
# filter: 只保留符合条件的元素
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4]
二、基本使用示例
2.1 过滤奇数(保留奇数)
def is_odd(n):
"""判断是否为奇数"""
return n % 2 == 1
numbers = [1, 2, 4, 5, 6, 9, 10, 15]
result = list(filter(is_odd, numbers))
print(result) # [1, 5, 9, 15]
2.2 过滤空字符串和 None
def not_empty(s):
"""判断字符串是否非空(去除空格后)"""
return s and s.strip()
data = ['A', '', 'B', None, 'C', ' ']
result = list(filter(not_empty, data))
print(result) # ['A', 'B', 'C']
2.3 使用 lambda 表达式简化
numbers = [1, 2, 3, 4, 5, 6]
# 过滤偶数
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6]
# 过滤大于3的数
greater_than_3 = list(filter(lambda x: x > 3, numbers))
print(greater_than_3) # [4, 5, 6]
三、惰性求值特性
filter() 返回的是一个迭代器,这意味着它是惰性计算的:
# 不会立即执行计算
filtered = filter(lambda x: x > 5, [3, 6, 2, 8])
print(filtered) # <filter object at 0x...>
# 只有在需要时才会计算(手动调用next或转换为列表)
print(next(filtered)) # 6
print(next(filtered)) # 8
# print(next(filtered)) # 抛出StopIteration
# 转换为列表(一次性计算所有)
filtered = filter(lambda x: x > 5, [3, 6, 2, 8])
print(list(filtered)) # [6, 8]
📌 内存优势:惰性求值意味着
filter()不会立即创建整个结果列表,对于大数据集可以显著节省内存。
四、实用案例
4.1 埃拉托斯特尼筛法(素数筛选)
这是一个经典的素数生成算法,使用filter()动态筛选出素数:
def primes():
"""生成无限素数序列的生成器"""
# 生成从3开始的奇数序列
def _odd_iter():
n = 1
while True:
n += 2
yield n
# 返回一个判断是否能被n整除的函数
def _not_divisible(n):
return lambda x: x % n != 0
yield 2 # 第一个素数是2
it = _odd_iter() # 初始序列:3,5,7,9,11,...
while True:
n = next(it) # 获取序列的第一个数(一定是素数)
yield n
# 用当前素数n过滤后续序列,留下不能被n整除的数
it = filter(_not_divisible(n), it)
# 打印100以内的素数
print("100以内的素数:")
for prime in primes():
if prime < 100:
print(prime, 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
4.2 筛选回文数
def is_palindrome(n):
"""判断一个数是否是回文数(正读反读相同)"""
s = str(n)
return s == s[::-1]
# 测试1-1000的回文数
palindromes = list(filter(is_palindrome, range(1, 1000)))
print("1~1000的回文数:", palindromes)
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, ..., 979, 989, 999]
# 测试验证
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("测试失败!")
4.3 筛选指定范围内的闰年
def is_leap_year(year):
"""判断是否为闰年"""
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
years = range(2000, 2025)
leap_years = list(filter(is_leap_year, years))
print(f"2000-2024年的闰年: {leap_years}")
# [2000, 2004, 2008, 2012, 2016, 2020, 2024]
4.4 筛选列表中符合条件的字典元素
# 学生数据
students = [
{"name": "Alice", "score": 85, "age": 20},
{"name": "Bob", "score": 92, "age": 22},
{"name": "Charlie", "score": 78, "age": 19},
{"name": "Diana", "score": 95, "age": 21},
]
# 筛选成绩大于等于90分的学生
high_scorers = list(filter(lambda s: s["score"] >= 90, students))
print("高分学生:", high_scorers)
# [{'name': 'Bob', 'score': 92, 'age': 22}, {'name': 'Diana', 'score': 95, 'age': 21}]
# 筛选年龄大于20岁的学生
older_students = list(filter(lambda s: s["age"] > 20, students))
print("年龄大于20的学生:", older_students)
# [{'name': 'Bob', 'score': 92, 'age': 22}, {'name': 'Diana', 'score': 95, 'age': 21}]
五、现代Python中的替代方案
虽然 filter() 仍然有用,但在许多情况下,列表推导式或生成器表达式可能更清晰、更Pythonic。
5.1 filter() vs 列表推导式
numbers = [3, 6, 2, 8, 1, 9]
# 使用filter
filtered_filter = list(filter(lambda x: x > 5, numbers))
# 等效的列表推导式
filtered_comp = [x for x in numbers if x > 5]
print(filtered_filter) # [6, 8, 9]
print(filtered_comp) # [6, 8, 9]
5.2 何时使用 filter()?
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 简单条件过滤 | 列表推导式 | 更直观、更Pythonic |
| 过滤函数已定义且复杂 | filter() | 代码更简洁 |
| 处理大数据集 | filter() | 返回迭代器,节省内存 |
| 函数式编程风格 | filter() | 符合函数式范式 |
5.3 生成器表达式的内存优势
import sys
# 列表推导式:立即创建列表,占用内存
list_comp = [x for x in range(1000000) if x % 2 == 0]
print(f"列表内存: {sys.getsizeof(list_comp)} bytes")
# filter:返回迭代器,几乎不占内存
filter_iter = filter(lambda x: x % 2 == 0, range(1000000))
print(f"filter内存: {sys.getsizeof(filter_iter)} bytes")
# 生成器表达式:同样内存友好
gen_exp = (x for x in range(1000000) if x % 2 == 0)
print(f"生成器内存: {sys.getsizeof(gen_exp)} bytes")
六、性能考虑
| 方法 | 内存效率 | 适用场景 |
|---|---|---|
filter() | 高(惰性求值) | 大数据集、函数已定义 |
| 列表推导式 | 中(立即创建列表) | 中小数据集、简单条件 |
| 生成器表达式 | 高(惰性求值) | 大数据集、简单条件 |
💡 建议:
- 对于简单过滤,列表推导式通常更清晰
- 对于大型数据集,
filter()或生成器表达式更节省内存- 如果需要多次使用过滤结果,转换为列表
七、练习:回文数筛选
def is_palindrome(n):
"""判断一个数是否是回文数"""
s = str(n)
return s == s[::-1]
# 测试1-1000的回文数
palindromes = list(filter(is_palindrome, range(1, 1000)))
print("1~1000的回文数:", palindromes)
# 测试验证
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("测试失败!")
八、扩展:itertools.filterfalse()
itertools模块提供了filterfalse()函数,它返回使函数返回False的元素:
from itertools import filterfalse
numbers = [1, 2, 3, 4, 5, 6]
# 过滤偶数(保留奇数)
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6]
# filterfalse:保留使函数返回False的元素(即奇数)
odds = list(filterfalse(lambda x: x % 2 == 0, numbers))
print(odds) # [1, 3, 5]
九、总结
| 知识点 | 要点 |
|---|---|
| 基本语法 | filter(function, iterable) |
| 返回值 | 迭代器(惰性求值) |
与map区别 | map转换元素,filter筛选元素 |
| 与列表推导式 | 列表推导式更Pythonic,filter内存效率更高 |
| 典型应用 | 素数筛选、回文数、数据清洗 |
| 性能特点 | 惰性求值,适合大数据集 |
核心要点:
- ✅
filter()根据判断函数筛选序列元素,返回迭代器 - ✅ 惰性求值特性使其内存效率高,适合大数据集
- ✅ 可与
lambda表达式结合,实现简洁的内联过滤 - ✅ 简单过滤场景,列表推导式通常更清晰
- ✅
itertools.filterfalse()可获取相反结果
掌握 filter() 函数,可以让你在处理序列数据时更加游刃有余,写出更具函数式风格的Python代码。
📚 相关推荐阅读
💡 Python 学习不走弯路!
体系化实战路线:基础语法 · 异步Web开发 · 数据采集 · 计算机视觉 · NLP · 大模型RAG实战
—— 全在 「道满PythonAI」!
如果这篇文章对你有帮助,欢迎点赞、评论、收藏,你的支持是我持续分享的动力!🎉