filter() 是 Python 内置的一个高阶函数,它的主要作用是过滤序列(例如列表、元组等),过滤掉不符合条件的元素,返回一个迭代器,其中包含所有符合指定条件的元素。

函数语法
filter(function, iterable)
参数详解
-
function: 一个函数,这个函数的返回值必须是布尔值(True或False)。filter()会将iterable中的每一个元素作为参数传递给这个function。function的返回值为True,则该元素会被保留。function的返回值为False,则该元素会被过滤掉。- 注意:
function参数是None,filter()函数会直接判断元素的“真值”(Truthiness),即,保留所有为True的元素,过滤掉所有为False的元素(如0,False,None, ,[], 等)。
-
iterable: 一个可迭代对象,例如列表、元组、集合、字符串等。filter()将会对这个对象中的每个元素进行筛选。
返回值
filter() 函数返回一个迭代器(iterator),而不是一个列表,迭代器是一个惰性序列,只有在需要时才会计算下一个值,这在处理大数据集时非常高效,因为它不会一次性在内存中生成所有结果。
使用示例
示例 1:使用 lambda 函数(最常见)
假设我们有一个数字列表,我们只想保留其中的偶数。

# 原始列表 numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 使用 lambda 定义一个判断是否为偶数的函数 # filter 会将 numbers 中的每个元素 n 传给 lambda,并检查 n % 2 == 0 是否为 True even_numbers_iterator = filter(lambda n: n % 2 == 0, numbers) # filter() 返回的是一个迭代器,我们不能直接打印它 # print(even_numbers_iterator) # 输出: <filter object at 0x...> # 为了看到结果,我们需要将迭代器转换为列表 even_numbers_list = list(even_numbers_iterator) print(even_numbers_list) # 输出: [2, 4, 6, 8, 10]
示例 2:使用独立的函数
如果逻辑比较复杂,我们可以先定义一个函数,然后再传给 filter()。
def is_positive(n):
"""判断一个数是否为正数"""
return n > 0
numbers = [-5, -2, 0, 1, 3, -8, 10]
# 使用定义好的函数进行过滤
positive_numbers_iterator = filter(is_positive, numbers)
# 转换为列表并打印
positive_numbers_list = list(positive_numbers_iterator)
print(positive_numbers_list)
# 输出: [1, 3, 10]
示例 3:function 参数为 None
当 function 为 None 时,filter() 会根据元素的“真值”来过滤。
mixed_values = [0, 1, False, True, "", "hello", None, [], [1, 2], {}]
# 过滤掉所有为 "假" 的值
truthy_values_iterator = filter(None, mixed_values)
# 转换为列表并打印
truthy_values_list = list(truthy_values_iterator)
print(truthy_values_list)
# 输出: [1, True, 'hello', [1, 2]]
解释:在 Python 中,0, False, None, 空字符串 , 空列表 [], 空字典 等都被视为 False,而其他值被视为 True。
示例 4:过滤字符串
我们可以用 filter() 来过滤掉字符串中的某些字符。

sentence = "Hello, World! 123" # 过滤掉所有非字母字符 # str.isalpha() 方法如果字符串中的所有字符都是字母则返回 True letters_iterator = filter(str.isalpha, sentence) # 转换为列表并打印 letters_list = list(letters_iterator) print(letters_list) # 输出: ['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd'] # 也可以重新组合成一个字符串 letters_string = "".join(letters_iterator) # 注意:上面的迭代器已经用完了,需要重新创建 letters_string = "".join(filter(str.isalpha, sentence)) print(letters_string) # 输出: HelloWorld
filter() vs. 列表推导式
在现代 Python 编程中,对于简单的过滤任务,列表推导式 通常被认为是更 Pythonic(更符合 Python 风格)且更易读的替代方案。
让我们用列表推导式重写第一个示例:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 使用列表推导式 even_numbers_list = [n for n in numbers if n % 2 == 0] print(even_numbers_list) # 输出: [2, 4, 6, 8, 10]
对比 filter() 和列表推导式:
| 特性 | filter() |
列表推导式 |
|---|---|---|
| 可读性 | 对于简单的 lambda,可读性尚可;对于复杂函数,可读性好。 |
通常被认为更直观、更易读,特别是对于初学者。 |
| 性能 | 在某些情况下(特别是 Python 2),filter() 可能更快,但在 Python 3 中,性能差异通常很小。 |
在 Python 3 中,性能通常与 filter() 相当或更好。 |
| 灵活性 | 只能进行“是/否”的二元过滤。 | 非常灵活,可以在过滤的同时对元素进行转换。 |
| 返回类型 | 返回一个迭代器,是惰性求值的,节省内存。 | 直接返回一个列表,是立即求值的。 |
什么时候选择 filter()?
-
代码可读性优先:当过滤逻辑非常复杂,用一个单独命名的函数来表示时,
filter(function, iterable)的形式可能比列表推导式更清晰。# 复杂逻辑用 filter + 函数 def is_valid_user(user): return user.get('is_active', False) and user.get('age', 0) >= 18 active_adult_users = filter(is_valid_user, list_of_all_users) # 对比列表推导式 active_adult_users = [user for user in list_of_all_users if is_valid_user(user)]在这个例子中,两者可读性差别不大,甚至列表推导式可能更受欢迎。
-
函数式编程风格:如果你倾向于函数式编程,并且已经有了一个现成的过滤函数,
filter()是一个很好的选择。
什么时候选择列表推导式?
- 简单过滤:对于绝大多数简单的过滤任务,列表推导式是首选,因为它更简洁。
- 需要转换元素:如果你想在过滤的同时修改元素,列表推导式是唯一的选择。
# 只能使用列表推导式 # 获取所有偶数的平方 even_squares = [n ** 2 for n in numbers if n % 2 == 0] # 输出: [4, 16, 36, 64, 100]
filter()是一个用于过滤序列的强大内置函数。- 它接受一个函数和一个可迭代对象,返回一个迭代器。
- 它是惰性求值的,适合处理大数据。
- 对于大多数日常任务,列表推导式因其出色的可读性和灵活性而更受推荐。
- 在需要复用复杂过滤逻辑或遵循特定编程风格时,
filter()仍然是一个有价值的选择。
