Back to Blog
Python

Python filter function: syntax and usage

python filter function: Learn how the Python filter function works, its syntax, and when to use it over list comprehensions, with practical examples.

Pythonfilterlambdalist comprehensioniterablesfunctional programming
A sieve filtering a stream of data items, with some passing through and others being left behind, representing the Python filter function.

The Python filter function is a built-in that returns an iterator containing only the elements from an iterable for which a given function returns a truthy value. It is a core tool in functional-style Python and is often used to keep data pipelines concise. The syntax is straightforward: filter(function, iterable). The function can be any callable that takes one argument, or it can be None to remove falsy values.

Basic Syntax and Behavior

filter takes two arguments: a callable and an iterable. It returns a filter object, which is a lazy iterator. That means the predicate is applied element by element as you iterate, not all at once. Here is the simplest form:

numbers = [1, 2, 3, 4, 5, 6] even = filter(lambda x: x % 2 == 0, numbers) print(list(even)) # [2, 4, 6]

The lambda checks each number for evenness. Because filter is lazy, the lambda is not executed until you consume the iterator, such as by converting it to a list or looping over it.

Using filter with Lambda Expressions

Lambdas are the most common callable passed to filter for simple predicates. They keep the logic inline and avoid defining a separate function for one-off checks. For example, selecting strings that start with a specific prefix:

words = ['apple', 'banana', 'apricot', 'cherry'] a_words = filter(lambda w: w.startswith('a'), words) print(list(a_words)) # ['apple', 'apricot']

Lambda expressions work well when the condition is short and does not need to be reused. If the same predicate appears in multiple places, a named function is clearer and easier to test.

Using filter with None as the Function

If you pass None as the callable, filter removes every item that is falsy. This is useful for stripping out 0, empty strings, None, False, and empty collections from a sequence. For instance:

values = [0, 1, '', 'hello', None, [], [1, 2]] non_empty = filter(None, values) print(list(non_empty)) # [1, 'hello', [1, 2]]

This behavior is equivalent to bool(item) for each element. It is a concise way to clean data, but be careful: if your data contains meaningful zeros or empty strings, filter(None, ...) will remove them too.

Filter with Existing Functions and Methods

You can pass any callable, not just lambdas. Built-in functions, class methods, or user-defined functions all work. For example, using str.isdigit to keep only digit strings:

tokens = ['123', 'abc', '456', 'def'] digits = filter(str.isdigit, tokens) print(list(digits)) # ['123', '456']

Methods that take an argument beyond the item itself need a lambda or functools.partial. For instance, filtering strings that contain a substring:

from functools import partial words = ['cat', 'dog', 'caterpillar', 'bird'] contains_cat = partial(str.__contains__, 'cat') result = filter(contains_cat, words) print(list(result)) # ['cat', 'caterpillar']

Using a named function often improves readability, especially when the predicate is complex or reused across the codebase.

Filter vs List Comprehension: When to Choose Which

List comprehensions can achieve the same result as filter and are often more readable because they keep the expression and condition together. For example, the even-number filter above can be written as:

even = [x for x in numbers if x % 2 == 0]

The main difference is that a list comprehension returns a list immediately, while filter returns a lazy iterator. This matters when you are chaining operations or working with large data sets. If you only need to iterate once, filter avoids building an intermediate list. If you need a reusable list, the comprehension is simpler. In general, prefer a list comprehension when you also want to transform the items, because filter only selects items without modifying them. For pure selection, both are valid; choose based on whether you want laziness and whether the predicate is already a named function.

Lazy Evaluation and Memory Behavior

Because filter returns an iterator, it does not materialize the entire result in memory. This is beneficial when the input iterable is large or infinite. For example, you can filter an infinite generator without exhausting memory:

def integers(): n = 0 while True: yield n n += 1 positive = filter(lambda x: x > 0, integers()) # Only take the first few for i in positive: if i > 5: break print(i) # prints 1,2,3,4,5

The predicate runs only as items are pulled from the iterator. This laziness also means that if the underlying iterable changes between iterations, the result can be inconsistent, so avoid using filter on mutable sequences that are modified during iteration.

Common Edge Cases and Pitfalls

One frequent mistake is assuming filter returns a list. It returns a filter object, so you must convert it explicitly if you need a list. Another pitfall is using filter with a function that returns a non-boolean value. The truthiness of the return value determines inclusion, which can lead to surprising results if the function returns numbers or strings. For instance, filter(lambda x: x % 2, [1,2,3]) keeps odd numbers because 1 % 2 is 1 (truthy) and 2 % 2 is 0 (falsy).

Also, when the predicate raises an exception, it propagates immediately during iteration. This can be useful for validation, but it means you need to handle exceptions if the input data is untrusted. Finally, remember that filter is lazy, so if you never consume the iterator, the predicate never runs. This is fine for most use cases, but it can hide bugs if you expect side effects from the predicate function.

python filter function: Practical Usage and Code Examples | RYUSLOG DEV