Working with filters
A closer look at the rule and the results.
The rule is a function.
A filter’s rule is called a predicate. It takes one item and usually answers True or False.
Give it a name
def keep(x):
return x > 2filter(keep, numbers)Or write it inline
lambda x: x > 2filter(lambda x: x > 2, numbers)lambda creates a small function. x is one item. The expression after : supplies the answer.
[1, 2, 3, 4, 5, 6][3, 4, 5, 6]The comparison is True for 3, 4, 5, and 6.
Pass keep, not keep(). The filter calls the rule for each item.
Can the items come from something other than a list?
Yes. An iterable supplies items one at a time. Lists, tuples, ranges, and strings all work. A string supplies individual characters:
list(filter(str.isupper, "HeLLo"))
# ["H", "L", "L"]str.isupper checks whether a character is uppercase. list() still makes a list; use "".join(filter(str.isupper, "HeLLo")) to get "HLL". Dictionaries supply keys by default.
Results arrive when you ask.
filter() creates an iterator: it remembers its position and gives you results one at a time. Creating it does not check the items yet. That’s called lazy evaluation.
numbers = [1, 2, 3, 4, 5]f = filter(lambda x: x > 2, numbers)1Not read2Not read3Not read4Not read5Not read
ReadyNo checks yet. Ask for the first match with next(f).
Already returned: []
One request can check several items.next(f) skips nonmatches until it finds one match.
Each result is used once.list(f) collects only what is left, not what you already read.
The source list stays unchanged. “New filter” creates a fresh iterator over that list. “Already returned” is a visual record for this example; the filter itself does not save past results.
What happens when there are no results left?
list(f) returns []. next(f) raises StopIteration, Python’s signal that the iterator is finished. Use next(f, None) if you want a default value instead.
Save matches = list(f) once if you need to use the matches repeatedly. The saved list is reusable; the filter is consumed.
“True” can mean more than True.
Python treats values as truthy or falsy, just as it does in an if statement. A filter keeps an item when the rule’s answer is truthy.
Falsy values include 0, False, None, and empty text or collections.
list(filter(None, values))
values · The original items, in order
0Skip1Keep""Skip"hello"KeepNoneSkipFalseSkip5Keep[1, "hello", 5]None in the rule’s place means “test each item itself.” It removes every falsy item, not just None.
What if my rule returns a number?
Python tests the answer’s truth value. With lambda x: x - 2, zero is falsy; both negative and positive nonzero numbers are truthy.
| Item | Rule’s answer | Decision |
|---|---|---|
1 | -1 | Keep 1 |
2 | 0 | Skip 2 |
3 | 1 | Keep 3 |
The result is [1, 3]: the original items, not the rule’s answers.
When would I use a comprehension or map?
Use a list comprehension for a simple selection you want as a list immediately. filter() lets you request matches as you need them. map() returns the function’s answers for every item.
list(filter(lambda x: x > 2, [1, 2, 3]))→ [3][x for x in [1, 2, 3] if x > 2]→ [3]list(map(lambda x: x > 2, [1, 2, 3]))→ [False, False, True]Put the details together.
Predict what stays and what is left to read.
Write the same rule inline
1 of 4You know what happens next.
Your rule chooses the items.
The iterator remembers where you stopped.
Truthiness decides what passes.
Review the lesson