Python高级特性:filter() 函数完全指南

Python高级特性:filter() 函数完全指南

优雅地过滤序列元素

前言

filter() 是 Python 的内置高阶函数,用于过滤序列 中的元素。它接收一个判断函数和一个可迭代对象,返回一个包含所有使函数返回 True 的元素的迭代器。与 map() 不同,filter() 的核心作用是筛选而非转换。

本文将系统讲解 filter() 的语法、惰性求值特性、与列表推导式的对比、以及素数筛选、回文数检测等实用案例,帮助你掌握这一函数式编程利器。

📚 本文内容基于道满PythonAI - filter() 函数详解与实用案例


一、filter() 函数基础

1.1 基本语法

python 复制代码
filter(function, iterable)
参数 说明
function 判断函数,接收一个参数,返回布尔值(True/False
iterable 可迭代对象(列表、元组、字符串等)
返回值 迭代器(Python 3),包含所有使函数返回 True 的元素

1.2 filter() 与 map() 的区别

函数 作用 返回结果
map() 将函数应用于每个元素 函数处理后的新值
filter() 根据条件筛选元素 原序列中符合条件的元素
python 复制代码
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 过滤奇数(保留奇数)

python 复制代码
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

python 复制代码
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 表达式简化

python 复制代码
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() 返回的是一个迭代器 ,这意味着它是惰性计算的:

python 复制代码
# 不会立即执行计算
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()动态筛选出素数:

python 复制代码
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 筛选回文数

python 复制代码
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 筛选指定范围内的闰年

python 复制代码
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 筛选列表中符合条件的字典元素

python 复制代码
# 学生数据
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 列表推导式

python 复制代码
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 生成器表达式的内存优势

python 复制代码
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()或生成器表达式更节省内存
  • 如果需要多次使用过滤结果,转换为列表

七、练习:回文数筛选

python 复制代码
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的元素:

python 复制代码
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内存效率更高
典型应用 素数筛选、回文数、数据清洗
性能特点 惰性求值,适合大数据集

核心要点

  1. filter() 根据判断函数筛选序列元素,返回迭代器
  2. 惰性求值特性使其内存效率高,适合大数据集
  3. ✅ 可与 lambda 表达式结合,实现简洁的内联过滤
  4. ✅ 简单过滤场景,列表推导式通常更清晰
  5. itertools.filterfalse() 可获取相反结果

掌握 filter() 函数,可以让你在处理序列数据时更加游刃有余,写出更具函数式风格的Python代码。


📚 相关推荐阅读


💡 Python 学习不走弯路!

体系化实战路线:基础语法 · 异步Web开发 · 数据采集 · 计算机视觉 · NLP · 大模型RAG实战

------ 全在 「道满PythonAI」


如果这篇文章对你有帮助,欢迎点赞、评论、收藏,你的支持是我持续分享的动力!🎉

相关推荐
医疗信息化王工2 小时前
基于ASP.NET Core的住院日志统计系统设计与实现
后端·layui·asp.net core·npoi·dapper
卜夋2 小时前
Rust学习 - 变量与类型
后端
hudson20222 小时前
work_mem: 这是一个陷阱!
后端·postgresql
Nturmoils2 小时前
实时决策时代,工业物联网需要什么样的数据库?
数据库·后端
用户8356290780512 小时前
Python 实现 Word 页眉页脚添加与自定义设置
后端·python
han_2 小时前
JavaScript设计模式(十):模板方法模式实现与应用
前端·javascript·设计模式
Rick19932 小时前
Spring Boot自动装配原理
java·spring boot·后端
得物技术2 小时前
立正请站好:一个组件复用 Skill 的工程化实践|得物技术
前端·架构·ai编程
神奇小汤圆2 小时前
Elasticsearch 与 JVM:生产环境调优实战指南
后端