What do Python's any() and all() return for an empty iterable?
answer
- Write out the loop each one is
- Which one needs to find a counterexample?
- Nothing failed, so the claim holds
- Vacuous truth over zero elements
- all([]) and any([]) disagree
basics
~10 sany() returns False and all() returns True on an empty iterable. all() is vacuously true because no element failed the test; any() found no truthy element, so there is nothing to report as True.
solid answer
~50 sBoth builtins reduce an iterable to a single `bool`, and their empty-input answers fall straight out of their definitions. `any()` scans for the first truthy element and returns `True` there, otherwise falls through to `False` — an empty iterable never enters the loop, so `any([])` is `False`. `all()` scans for the first falsy element and returns `False` there, otherwise falls through to `True`, so `all([])` is `True`. That is vacuous truth: over zero elements, nothing fails. Both also short-circuit, stopping at the first decisive element rather than reading the whole input, and both return a real `bool`, never the element that decided it. The practical trap is validation code shaped like `if all(check(x) for x in batch)`, which silently approves an empty batch — guard the emptiness separately when "at least one" is part of the requirement.
code
pycon · 8 lines>>> any([])
False
>>> all([])
True
>>> all(x > 0 for x in [])
True
>>> any(x > 0 for x in [])
Falsego deeper
Recall the two results cold: any([]) is False, all([]) is True. Be ready to justify the second one in a sentence — no element failed, so the claim holds.
Explain the mechanics behind the results by writing out the equivalent loop, and mention short-circuiting: both stop at the first decisive element and both return a bool rather than the element itself.
Show where the empty case causes real damage — a permission or validation gate built on all() that silently approves an empty requirement list — and how you would make the non-empty requirement explicit in review.
Own the convention argument: vacuous truth is what preserves all(xs + ys) == all(xs) and all(ys), so codebases should encode "at least one" as its own check rather than redefining the reduction with a helper everyone must remember.
`any(iterable)` and `all(iterable)` are builtins that collapse an iterable of arbitrary values into a single `bool`. Almost every question about them is answered by writing out the two loops they are equivalent to: ```python def any_(iterable): for element in iterable: if element: return True return False def all_(iterable): for element in iterable: if not element: return False return True ``` ### Why the empty answers are what they are If the iterable yields nothing, neither loop body runs even once, so control falls through to the final `return`. `any()` falls through to `False`; `all()` falls through to `True`. There is no special case in the C implementation for empty input — the answers are the natural identity element of each reduction, exactly as `sum([])` is `0` and `math.prod([])` is `1`. The `all()` case is the one candidates get wrong, and it has a name: vacuous truth. `all()` asserts "no element fails", and over zero elements nothing fails, so the assertion holds. The convention is not arbitrary; it is what keeps the useful algebraic property that splitting an input in two never changes the answer. `all(xs + ys)` equals `all(xs) and all(ys)` for every split, including the split where one half is empty — which only works if the empty half evaluates to `True`. The mirrored property holds for `any()` with `or` and `False`. The two are duals, related by De Morgan's laws: `all(xs)` is the same as `not any(not x for x in xs)`, and `any(xs)` is the same as `not all(not x for x in xs)`. Recognising that pairing is often enough to reconstruct any of the four empty-input answers under interview pressure. ### Short-circuiting Neither builtin promises to read the whole input. `any()` returns the moment it sees a truthy element; `all()` returns the moment it sees a falsy one. The number of elements actually examined is therefore data-dependent — anywhere from one to all of them. This is why the argument you hand them matters so much: a lazy source lets the short-circuit skip work, while an eagerly built container has already paid for every element before the call begins. Because they consume the iterable through the normal iteration protocol, they work with any iterable — a `list`, a `set`, a file object, a generator. When the argument is a one-shot iterator, short-circuiting leaves it partially consumed rather than exhausted, which matters if anything downstream iterates it again. ### The return value is a bool, not an element A frequent misconception is that `any()` behaves like a chain of `or` operators. It does not. The `or` and `and` operators return one of their *operands* (`0 or 'x'` is `'x'`), whereas `any()` and `all()` always return the canonical `True` or `False`. If you need the element that decided the outcome rather than the verdict, `any()` is the wrong tool. What counts as truthy is decided by the standard truth test applied to each element — empty containers, zero and `None` are falsy, most other objects are truthy — so `any(['', 0, 'x'])` is `True` because the last element is a non-empty string. ### Where the empty case actually bites The realistic bug is a validation or gating check written as: ```python if all(passes(item) for item in batch): approve(batch) ``` An empty `batch` approves. The same shape appears in permission checks (`all(user.has(p) for p in required)` grants everything when `required` is empty) and in health checks (`all(probe.ok for probe in probes)` reports healthy when no probes were registered). The fix is to make the emptiness requirement explicit rather than hoping the reduction covers it: test the container first with `if batch and all(...)`, or count the items in the same pass when the source is a one-shot iterator you cannot cheaply re-test. Symmetrically, `any()` on empty input returning `False` is usually the harmless direction — it fails closed — which is part of why `all()` is where the surprise lives. This behaviour has been stable for the entire Python 3 line and is unchanged on 3.14; it is one of the few corners of the language with no version story at all. ### Reading them in real code Because both take an iterable rather than a variadic argument list, `any(a, b)` is a `TypeError`, not a two-way or; the arguments must be wrapped in a container or produced by an expression. And because they consume the iterable through ordinary iteration, they work on a `dict` (iterating its keys), a `set`, a file object (its lines) and any user-defined object implementing `__iter__` — the truth test is applied to whatever those yield, which is why `any(some_dict)` answers "is any key truthy" and not "is the dict non-empty". When emptiness is the actual question, `if container:` says it directly.
- Does any() evaluate every element before it returns?No. It returns `True` the moment it sees a truthy element and never looks at the rest, so the number of elements examined depends on the data. `all()` mirrors this and stops at the first falsy element. Only when the answer is `False` for `any()` (or `True` for `all()`) has the whole iterable been consumed.
- How would you require that a batch is non-empty and every item passes?Make the emptiness requirement explicit rather than leaning on the reduction: `if batch and all(check(x) for x in batch)`. If the source is a one-shot iterator you cannot re-test, count while you check — for example total the passes and the items in one loop, then require the count to be positive and equal.
- How are any() and all() related to each other?They are De Morgan duals: `all(xs)` equals `not any(not x for x in xs)`, and `any(xs)` equals `not all(not x for x in xs)`. That relationship also explains the empty-input answers — negating `False` for empty `any()` gives `True` for empty `all()`.
"Every parcel in this van is damaged" is true of an empty van — you cannot point at a parcel that isn't. "Some parcel in this van is damaged" is false for the same reason.
saying these in an interview costs you the question
- Says all() on an empty list returns False
- Says any() or all() raises on empty input
- Claims both always scan the entire iterable
- Thinks any() returns the truthy element, not a bool
- Treats any(x) as a non-empty check on the container
- Confuses them with the or/and operators returning operands