python any vs all: Choosing the Right Built-in
python any vs all: Compare Python's any() and all() built-ins: syntax, short-circuit behavior, edge cases with empty iterables, and when to use each.
Python's any() and all() are built-in functions that reduce an iterable of values to a single boolean. They look similar at a glance, but their semantics differ in a way that matters for validation logic, data filtering, and condition checks. Understanding python any vs all comes down to knowing what each function actually tests and how it behaves with empty input.
What any() and all() Actually Test
any(iterable) returns True if at least one element in the iterable is truthy. all(iterable) returns True only if every element is truthy.
values = [0, 1, 2] print(any(values)) # True, because 1 is truthy print(all(values)) # False, because 0 is falsy
Both functions accept any iterable, not just lists. Tuples, sets, dictionaries, and generator expressions all work. For dictionaries, iteration happens over keys by default:
config = {"debug": True, "verbose": False} print(any(config)) # True, because "debug" is a non-empty string print(all(config)) # True, because both keys are non-empty strings
If you need to check dictionary values instead, call .values() explicitly. This is a common mistake when developers assume any(config) inspects the values.
The core difference is summarized here:
| Behavior | any() | all() |
|---|---|---|
Returns True when | at least one element is truthy | every element is truthy |
| Short-circuits on | first truthy element | first falsy element |
| Empty iterable result | False | True |
Short-Circuit Evaluation and Runtime Behavior
Both functions stop evaluating as soon as the result is determined. any() returns True at the first truthy element and does not examine the rest. all() returns False at the first falsy element and stops there.
def check(item): print(f"checking {item}") return item > 0 numbers = [1, 2, 3] print(any(check(n) for n in numbers))
The output shows that check runs only for the first element because 1 > 0 is True, so any() short-circuits immediately. This behavior matters when the predicate has side effects or when evaluating each element is expensive.
Short-circuiting also means that if the first element determines the result, the remaining elements are never processed. For all(), a single False early in the iterable skips all subsequent work. This is the same lazy evaluation principle that makes generator expressions useful here.
Using Generator Expressions to Avoid Building Lists
Passing a generator expression instead of a list comprehension avoids allocating a temporary list. This is especially relevant when the iterable is large or when the predicate is expensive.
data = [10, 20, 0, 30] has_zero = any(x == 0 for x in data) all_positive = all(x > 0 for x in data)
The generator expression (x == 0 for x in data) produces values one at a time. any() consumes only as many as needed before finding a truthy value. A list comprehension would build the entire list of booleans first, then pass it to any(), which wastes memory and time.
The same pattern works with all():
records = [{"id": 1, "active": True}, {"id": 2, "active": True}] all_active = all(r["active"] for r in records)
This is the idiomatic way to validate a collection of objects without writing an explicit loop.
Edge Cases: Empty Iterables and Truthiness
The behavior with empty iterables is a common source of confusion. any([]) returns False, because there is no truthy element to find. all([]) returns True, because there is no falsy element to disprove the claim that all elements are truthy.
This is not a quirk; it follows from the mathematical definitions. The universal quantifier over an empty set is true, and the existential quantifier over an empty set is false. In practice, this means all() on an empty collection passes validation, which is often the desired behavior for checks like "all required fields are present" when no fields are required.
Truthiness also matters. The functions test truthiness, not equality with True. So any([1, "x", [0]]) returns True because all three values are truthy, even though none of them is the boolean True. Similarly, all([1, "x", [0]]) returns True. Only falsy values—0, 0.0, "", [], {}, None, False—cause all() to return False.
Common Validation Patterns
A typical use case is validating that all required fields are present in a dictionary:
required_fields = ["name", "email", "age"] user = {"name": "Ada", "email": "ada@example.com", "age": 36} missing = [field for field in required_fields if not user.get(field)] if missing: print(f"Missing fields: {missing}")
The any() and all() versions are more compact but less informative:
if not all(user.get(field) for field in required_fields): print("Some required fields are missing")
The tradeoff is that all() tells you whether validation failed but not which field failed. If the caller needs to know what to fix, a loop or a list comprehension that collects missing fields is more useful. Use any() and all() when a single boolean answer is sufficient.
Performance Considerations
The main performance advantage of any() and all() over an explicit loop is short-circuiting combined with generator expressions. A manual loop that breaks early achieves the same result, but the built-ins are more concise and less error-prone.
There is no meaningful performance difference between any() and all() themselves; both are implemented in C and iterate at the same speed. The difference in runtime cost comes from how many elements each function actually visits, which depends on the data. For any(), the worst case is when no element is truthy, forcing it to scan the entire iterable. For all(), the worst case is when every element is truthy.
If the predicate is expensive, ordering the iterable so that the deciding value appears early can reduce work. For example, if most records are inactive and you are checking whether any record is active, placing inactive records first makes any() return False after scanning everything anyway. There is no way to avoid that without changing the data structure. If you need to know which elements failed, any() and all() are the wrong tool.
When to Use a Manual Loop Instead
any() and all() are not always the right choice. If the logic inside the loop is more complex than a single predicate, or if you need to collect information about why a condition failed, an explicit loop is clearer.
def validate_user(user): for field in ("name", "email", "age"): if not user.get(field): return False, f"missing {field}" return True, None
This version returns both the failure and the reason. all() cannot do that without additional code. The built-ins are best for boolean checks where the caller only needs a yes-or-no answer. For anything that requires diagnostics, a loop or a comprehension that gathers details is more maintainable.
Another case where a manual loop wins is when the predicate has side effects that must happen in a specific order, or when the number of iterations must be tracked. any() and all() hide the iteration count, so debugging becomes harder if the predicate depends on the index.