How can you **check whether all items match a condition** in Python?
And how can you check whether *any* item matches a condition?

You might think to do something like this:

```
all_good = True
for item in iterable:
if not condition(item):
all_good = False
break
```

Or something like this:

```
any_bad = False
for item in iterable:
if condition(item):
any_bad = True
break
```

But there are two built-in Python functions that can help make those code blocks more descriptive and more readable.
Let's talk about using **Python's any and all functions** to check whether all iterable items match a condition.

This function accepts a list (or iterable) of numbers and checks whether all the numbers are between `0`

and `5`

(inclusive):

```
def ratings_valid(ratings):
for rating in ratings:
if rating < 0 or rating > 5:
return False
return True
```

This code:

- Loops over all given numbers (using a
`for`

loop) - Returns
`False`

as soon as a negative number or a number greater than 5 is found (using an`if`

statement to check that condition) - Returns
`True`

if all numbers are between`0`

and`5`

Note that this function **returns as soon as it finds an invalid number**, so it *only* iterates all the way through the number range if all the numbers are valid.

`any`

and `all`

functions in PythonLet's first look at a **refactoring** of our loop that checks a condition for each item and then discuss what we did, **why we did it**, and how we did it.

**Spoiler alert!** ⚠️ We're about to look at the code we'll *eventually* end up with and then we'll step back and **refactor our way to that code**.

We started with this:

```
def ratings_valid(ratings):
for rating in ratings:
if rating < 0 or rating > 5:
return False
return True
```

We're going to end up either this:

```
def ratings_valid(ratings):
return not any(
rating < 0 or rating > 5
for rating in ratings
)
```

Or we'll end up with this (which is even more readable):

```
def ratings_valid(ratings):
return all(
0 <= rating <= 5
for rating in ratings
)
```

Okay, let's break this code down to see how it works.
First we need to talk about the `any`

and `all`

functions.
Then we'll talk about why `any`

and `all`

tend to be used with generator expressions, how to choose between them.
Finally, we'll wrap up with a cheat sheet.

`any`

functionPython has a built-in `any`

function that returns `True`

**if any items are truthy**

```
>>> any([True, False, False, True, False])
True
>>> any([False, False, False, False, False])
False
>>> any(['', '', ''])
False
>>> any(['', 'Python', ''])
True
```

Truthy typically means non-empty or non-zero, but for our purposes you can think of it pretty much the same as `True`

.

Python's `any`

is equivalent to this:

```
def any(iterable):
for element in iterable:
if element:
return True
return False
```

Notice the similarity between `any`

and our `ratings_valid`

function: their structure is *very similar*, but not quite the same.

The `any`

function checks for the truthiness of each item in a given iterable, but we need something a little more than that: **we need to check a condition on each element**.
Specifically, we need to check whether a number is between `0`

and `5`

.

`all`

functionPython also has a built-in `all`

function that returns `True`

if **all items are truthy**.

```
>>> all([True, False, True, True, False])
False
>>> all([True, True, True, True, True])
True
>>> all(['Python', 'is', 'neat'])
True
>>> all(['', 'Python', 'is', 'neat'])
False
```

Python's `all`

is equivalent to this:

```
def all(iterable):
for element in iterable:
if not element:
return False
return True
```

The `any`

and `all`

functions are two sides of the same coin:

`any`

returns`True`

as soon as it finds a match`all`

returns`False`

as soon as it finds a non-match

The `any`

and `all`

functions accept an iterable and check the truthiness of each item in that iterable.
These functions are typically used with iterables of **boolean values**.

We could re-implement our `ratings_valid`

function by building up a list of boolean values and then passing those values to `any`

:

```
def ratings_valid(ratings):
rating_is_invalid = []
for rating in ratings:
rating_is_invalid.append(rating < 0 or rating > 5)
return not any(rating_is_invalid)
```

Or we could copy-paste that `for`

loop into a list comprehension:

```
def ratings_valid(ratings):
return not any([
rating < 0 or rating > 5
for rating in ratings
])
```

That code is shorter, but there's a problem: we're **building up a new list just to loop over it once**!
This is less efficient than our original approach!

Our original approach only looped all the way through the list if all ratings were valid (see the `return`

within the `for`

loop).

```
def ratings_valid(ratings):
for rating in ratings:
if rating < 0 or rating > 5:
return False
return True
```

Let's fix this inefficiency by turning our list comprehension into a **generator expression**.

A generator expression is like a list comprehension, but instead of making a list it makes a **generator object**.

```
def ratings_valid(ratings):
return not any((
rating < 0 or rating > 5
for rating in ratings
))
```

We can actually even drop the double parentheses and still have valid Python code:

```
def ratings_valid(ratings):
return not any(
rating < 0 or rating > 5
for rating in ratings
)
```

It's *so common* to pass a generator expression directly into a function call that the Python core developers added this feature *just* for this use case.

Generators are **lazy iterables**: they don't compute the items they contain until you loop over them.
Instead they compute their values item-by-item.
This allows us to stop computing as soon as the `any`

function finds a truthy value!

There's *one* more thing we can do to improve the readability of this code: we could switch to using Python's `all`

function.

`any`

and `all`

We started with a `for`

loop, an `if`

statement, a `return`

statement within our loop, and a `return`

statement at the end of our loop:

```
def ratings_valid(ratings):
for rating in ratings:
if rating < 0 or rating > 5:
return False
return True
```

We turned all that into a generator expression passed to the `any`

function:

```
def ratings_valid(ratings):
return not any(
rating < 0 or rating > 5
for rating in ratings
)
```

Note that we negated the final result (see the `not`

in `return not any...`

)

In English, this reads "there is *not* any rating outside the target range".

Using the `all`

function we're able to lose that negation:

```
def ratings_valid(ratings):
return all(
not (rating < 0 or rating > 5)
for rating in ratings
)
```

Or if we rely on Python's chained comparisons, we could write:

```
def ratings_valid(ratings):
return all(
0 <= rating <= 5
for rating in ratings
)
```

In English, this reads "all the ratings are within the target range".

These two statements are equivalent in Python:

```
>>> all_match = all(condition(x) for x in iterable)
>>> all_match = not any(not condition(x) for x in iterable)
```

And these two statements are equivalent as well:

```
>>> any_match = any(condition(x) for x in iterable)
>>> any_match = not all(not condition(x) for x in iterable)
```

Typically one of your `any`

or `all`

expressions will read more clearly than the other one.
In our case, it's the `all`

expression that reads more clearly.

`any`

and `all`

in an `if`

statementI've mostly been showing `any`

and `all`

used in a `return`

statement, but that's actually *not* its most readable use.

If you don't find the behavior of these functions to be intuitive, you might find them easier to understand when used in an `if`

statement.

For example let's say we have an `is_valid_rating`

function like this:

```
def is_valid_rating(rating):
return 0 <= rating <= 5
```

We could use that function to write an `if`

statement like this:

```
if all(is_valid_rating(r) for r in ratings):
print("All the ratings are valid")
else:
print("Not all ratings are valid")
```

In English I would describe that code as checking whether "all ratings are valid" and then printing based on the result.

Compare that code to this:

```
all_valid = True
for r in ratings:
if not is_valid_rating(r):
all_valid = False
break
if all_valid:
print("All the ratings are valid")
else:
print("Not all ratings are valid")
```

In English this reads as "loop over all ratings and set `all_valid`

to `False`

if an invalid rating is found or set it to `True`

otherwise" and then print based on the value of `all_valid`

.

This `for`

loop doesn't translate into English nearly as easily as that `if`

statement with `all`

do!
I very much prefer this first approach of using a generator expression with `all`

because I find it **more descriptive** than the equivalent `for`

loop.

Python's `any`

and `all`

functions are for **checking a condition for every item in a list** (or any other iterable).
While `any`

and `all`

are handy, sometimes there's an even simpler condition checking tool available.

For example this loop:

```
>>> numbers = [2, 1, 3, 4, 7, 11]
>>> has_five = False
>>> for n in numbers:
... if n == 5:
... has_five = True
... break
...
```

Could be written like this:

```
>>> numbers = [2, 1, 3, 4, 7, 11]
>>> has_five = any(n == 5 for n in numbers)
```

But this could be simplified even further.
We're trying to check whether a given number is contained in the `numbers`

list.

The `in`

operator is made exactly for this purpose:

```
>>> numbers = [2, 1, 3, 4, 7, 11]
>>> has_five = 5 in numbers
```

Python's `in`

operator is for containment checks.
Anytime you need to ask whether a particular item is contained in a given iterable, the `in`

operator is the tool to reach for.

Additionally, when you find yourself searching for a matching item in an iterable, in general you may want to question whether you should use a dictionary instead.

`any`

and `all`

Here's a quick cheat sheet for you.

This code uses a `break`

statement because we're not returning from a function: using `break`

stops our loop early just as `return`

does.

`any`

and `all`

functionsPython's `any`

and `all`

functions were *made* for use with generator expressions (discussed here & here) and they're rarely used without them.

The next time you need to **check whether all items match a condition**, try Python's `any`

or `all`

functions along with a generator expression.

For more of my recommendations on how to use Python's built-in functions, see Built-in functions in Python.

Need to **fill-in gaps** in your Python skills?

Sign up for my Python newsletter where **I share one of my favorite Python tips every week**.

✕

↑

A Python Tip Every Week

Need to **fill-in gaps** in your **Python skills**? I send weekly emails designed to do just that.