Подробный гайд: Разбираем, почему all() в Python возвращает True - Часть 2
8. all() и короткие замыкания
all() останавливается, как только находит первый ложный элемент.
Пример:
def check(x):
print("Проверяю", x)
return x
all(check(x) for x in [1, 2, 0, 3])
Вывод будет примерно таким:
Проверяю 1
Проверяю 2
Проверяю 0
До 3 дело не дойдёт, потому что 0 ложный, и all() сразу вернул False. Это важно для производительности и для работы с бесконечными последовательностями. Но если все элементы истинны, all() придётся дойти до конца.
9. Разница между all() и any()
all()возвращаетTrue, если все элементы истинны.any()возвращаетTrue, если хотя бы один элемент истинен.
Таблица:
all([]) # True
any([]) # False
all([0]) # False
any([0]) # False
all([1]) # True
any([1]) # True
all([1, 0]) # False
any([1, 0]) # True
Логически:
all(iterable)
похоже на:
element_1 and element_2 and element_3 and ...
А:
any(iterable)
похоже на:
element_1 or element_2 or element_3 or ...
Для пустого списка:
all([]) # True, потому что нет ложных элементов
any([]) # False, потому что нет истинных элементов
10. Примеры из практики
Проверка, что все числа положительные
numbers = [1, 2, 3, 4]
all(x > 0 for x in numbers) # True
Если список пуст:
numbers = []
all(x > 0 for x in numbers) # True
Если нужно запретить пустой список:
numbers = []
if numbers and all(x > 0 for x in numbers):
print("Все числа положительные")
else:
print("Список пуст или есть неположительные числа")
Проверка, что все строки непустые
fields = ["Иван", "Иванов", "Москва"]
all(fields) # True
Если хотя бы одна пустая строка:
fields = ["Иван", "", "Москва"]
all(fields) # False
Проверка, что все строки содержат только цифры
codes = ["123", "456", "789"]
all(code.isdigit() for code in codes) # True
Если есть нецифровая строка:
codes = ["123", "45a", "789"]
all(code.isdigit() for code in codes) # False
Проверка, что все ключи существуют
data = {"name": "Иван", "age": 30}
required = ["name", "age"]
all(key in data for key in required) # True
Если ключа не хватает:
required = ["name", "age", "email"]
all(key in data for key in required) # False
Проверка, что все файлы существуют
from pathlib import Path
files = ["a.txt", "b.txt"]
all(Path(file).exists() for file in files)
Если список пуст, результат будет True.
Поэтому если файлов обязательно должен быть хотя бы один:
files = []
bool(files) and all(Path(file).exists() for file in files)
11. Частые ошибки
Ошибка 1: думать, что all([]) должен вернуть False
all([]) # True
Это не баг. Это логическое поведение: нет элементов — нет нарушений.
Если нужно, чтобы пустая коллекция считалась ошибкой:
if items and all(condition(x) for x in items):
...
Ошибка 2: передавать список вместо генератора, когда это не нужно
Можно писать так:
all([x > 0 for x in numbers])
Но лучше так:
all(x > 0 for x in numbers)
Почему?
Первый вариант создаёт весь список результатов в памяти:
[True, True, False, ...]
Второй вариант использует генератор и не создаёт лишний список целиком.
Ошибка 3: неправильно писать составное условие
Неправильно:
all(x == 1 or 2 for x in values)
Правильно:
all(x == 1 or x == 2 for x in values)
Или:
all(x in (1, 2) for x in values)
Ошибка 4: ожидать, что all() проверяет равенство элементов
all([5, 5, 5]) # True
Это не значит, что все элементы равны между собой. Это значит, что все элементы истинны.
Если нужно проверить, что все элементы равны:
values = [5, 5, 5]
all(x == values[0] for x in values)
Или безопаснее для пустого списка:
def all_equal(values):
iterator = iter(values)
try:
first = next(iterator)
except StopIteration:
return True # или False, если пустой список должен быть ошибкой
return all(x == first for x in iterator)
12. Как проверить, что коллекция не пустая и все элементы истинны
Иногда нужно именно:
- чтобы элементы были;
- чтобы все они были истинны.
Простой вариант:
def all_and_not_empty(iterable):
return bool(iterable) and all(iterable)
Но это работает не для всех итерируемых объектов. Например, генератор нельзя надёжно проверить через bool(), потому что генератор всегда истинен как объект.
Более универсальный вариант:
def all_and_not_empty(iterable):
iterator = iter(iterable)
try:
first = next(iterator)
except StopIteration:
return False
return bool(first) and all(iterator)
Примеры:
all_and_not_empty([]) # False
all_and_not_empty([1, 2]) # True
all_and_not_empty([1, 0]) # False
all_and_not_empty([0, 1]) # False
13. Почему all() может вернуть True в вашем коде: чек-лист
Если all() возвращает True, хотя вы ожидали False, проверьте:
1. Не пустой ли итерируемый объект?
print(list(iterable))
2. Правильное ли условие внутри генератора?
for x in iterable:
print(x, condition(x))
3. Не используете ли вы конструкцию вроде:
x == 1 or 2
вместо:
x == 1 or x == 2
- Не передаёте ли вы уже исчерпанный итератор?
- Не проверяете ли вы просто истинность объектов, хотя хотели проверять их содержимое?
- Не ожидаете ли вы, что
all()проверяет равенство элементов?
14. Короткий итог
all() возвращает True, если:
все элементы итерируемого объекта истинны
или если:
элементов нет вообще
Поэтому:
all([]) # True
Это нормально, потому что нет ни одного элемента, который был бы ложным.
Главная формула:
all(iterable) == True
означает:
не нашлось ни одного ложного элемента
А не:
элементы обязательно существуют
и не:
элементы равны True
Если вам нужно, чтобы пустая коллекция давала False, используйте проверку:
if iterable and all(condition(x) for x in iterable):
...
Мы делимся этой технической информацией, чтобы помочь вам в решении задач — используйте её с пониманием. Статья носит рекомендательный характер, поэтому, пожалуйста, применяйте описанные методы осмотрительно.