any и all в Python: проверка без ручного цикла
any и all отвечают на вопросы «есть ли хоть один» и «все ли до единого» одной строкой — вместо цикла с булевым флагом.
Редакция Питоники
Задачи «есть ли в списке хоть один плохой элемент» и «все ли элементы хорошие» встречаются постоянно: есть ли двойки в журнале, все ли поля формы заполнены, остались ли товары на складе. До сих пор ответ искали циклом с булевым флагом: завести переменную, менять её в цикле, проверить после. Python умеет отвечать на оба вопроса одной функцией: any — «хотя бы один», all — «все до единого». Функция any возвращает True, если условие выполнилось хотя бы для одного элемента, а all — если для всех без исключения.
any: хотя бы один
Сравним оба подхода на журнале оценок: нужно узнать, есть ли в нём двойки.
marks = [4, 2, 5, 3]
has_bad = False
for m in marks:
if m == 2:
has_bad = True
break
print(has_bad)
print(any(m == 2 for m in marks))
True True
Сверху — ручной способ, который мы писали в уроках про break и аккумуляторы: флаг has_bad стартует как False, цикл ходит по оценкам, переворачивает флаг, найдя двойку, и останавливается — дальше искать бессмысленно. Снизу — та же проверка одной строкой. any(...) принимает последовательность значений True и False и отвечает True, если среди них есть хотя бы один True. Внутрь скобок передана заготовка m == 2 for m in marks — генератор, который выдаёт результат сравнения для каждой оценки; генераторы списков — близкий родственник, разница только в квадратных скобках.
print(any([0, 0, 5]))
print(any([0, '', []]))
print(any([False, False]))
True False False
any годится и для готовых значений, без условия: непустая строка, ненулевое число и непустой список истинны, нули и пустые значения ложны. Поэтому any([0, '', []]) вернул False: среди значений нет ни одного истинного. Но чаще интересует не «есть ли хоть одно ненулевое», а «выполнено ли условие» — тогда внутрь передают генератор с условием, как в примере с оценками.
all: все до единого
all работает зеркально: True только если истинны все элементы сразу.
marks = [4, 5, 4, 5]
print(all(m >= 3 for m in marks))
marks = [4, 5, 2, 5]
print(all(m >= 3 for m in marks))
True False
Вопрос одинаковый — все ли оценки не хуже тройки, — а ответы разные. Первый журнал целиком проходит проверку. Во втором живёт двойка, и одного нарушителя достаточно: правило «все до единого» ломается первым же неподходящим элементом, остальные можно даже не смотреть.
print(any([]))
print(all([]))
False True
Пустая последовательность — каверзный случай, и его стоит просто запомнить. any([]) отвечает False: подходящих не нашли. all([]) отвечает True — и это логично, если читать all как «не найдено ни одного нарушителя»: в пустом списке нарушителей нет, проверка пройдена. Поэтому перед all на пустых данных стоит лишний раз подумать: True на пустом списке может оказаться не тем ответом, которого ждёт программа.
any и all на практике
Соберём две живые проверки. Первая — анкета: все ли ответили «да». Вторая — форма регистрации: заполнены ли все поля и есть ли в форме телефон.
answers = ['да', 'нет', 'да']
print(any(a == 'да' for a in answers))
print(all(a == 'да' for a in answers))
True False
Хотя бы один согласился — any ответил True. Все согласились — нет, есть один «нет», и all ответил False. Два вопроса, две функции, ноль циклов с флагами.
form = {'name': 'Анна', 'email': '', 'city': 'Москва'}
filled = all(v != '' for v in form.values())
print('Все поля заполнены:', filled)
has_phone = any(k == 'phone' for k in form)
print('Есть телефон:', has_phone)
Все поля заполнены: False Есть телефон: False
Обход словаря по values() отдаёт значения полей, и all проверяет, что пустых среди них нет: email ввели пустой строкой, форма не готова к отправке. Обход по ключам нашёл бы телефон через any — но такого поля в форме нет, и ответ False. Оба ответа собраны без единого ручного цикла: их пишут функции.
def check(n):
print('проверяем', n)
return n > 2
print(any(check(n) for n in [3, 5, 1]))
проверяем 3 True
Вывод показывает главное устройство any: проверена только тройка, а пятёрка и единица не трогались. Как только генератор выдал первый True, функция остановилась — ответ уже ясен. Это называется коротким замыканием, и оно работает в обе стороны: any останавливается на первом True, all — на первом False. На длинных списках это заметная экономия: до половины данных проверка может не дойти.
any и all на словаре
Словарь проверяется так же, как список, только обход выбирают осознанно: values() отдаёт сами значения, keys() — ключи. Для проверки «есть ли дорогая позиция» нужен обход по значениям, а для «есть ли поле с таким именем» — по ключам.
prices = {'хлеб': 50, 'сыр': 300, 'молоко': 80}
print(any(p > 200 for p in prices.values()))
print(all(p > 0 for p in prices.values()))
True True
Первая строка — «есть ли что-то дороже двухсот»: сыр стоит 300, ответ True. Вторая — «все ли цены положительные»: пустых и отрицательных нет, ответ True. Одна и та же функция, два разных вопроса к тем же данным.
form = {'name': 'Анна', 'email': '', 'city': 'Москва'}
print(any(k == 'phone' for k in form))
print(all(form.values()))
False False
Телефона в форме нет — первый ответ False. Второй проверяет значения, и пустая строка email оказалась ложной, поэтому all ответил False. Покажите any на значениях — и вы получите True: пустая строка не мешает, если нужен хоть один непустой элемент. Одна и та же форма, два разных вопроса к ней.
Сколько подходящих: sum по булевым значениям
any и all отвечают на вопросы «есть хоть один» и «все до единого». Третий вопрос — «а сколько именно» — они не решают, но решает их ближайший родственник: встроенная sum. В Python логические значения(True и False) — это числа 1 и 0.
flags = [True, False, True]
print(sum(flags))
print(sum(1 for f in flags if f))
2 2
Два ответа совпали: True посчитали как единицу, False — как ноль. Второй вариант с генератором даёт то же самое, но работает и с не-булевыми значениями: если в списке лежат числа или строки, sum напрямую сложит их и получит ерунду, а sum(1 for ...) посчитает только успешные проверки. Практический вывод: когда нужен ответ «сколько прошло», sum(1 for ...) надёжнее, чем sum по сырым значениям.
Сложные условия: вложенные проверки
Условие внутри генератора может быть сколь угодно сложным, и any с ним справляется. Проверить «есть ли нечётное, которое больше пяти» — одна строка, где внутри условия стоит and.
nums = [3, 7, 9]
print(any(n % 2 == 0 for n in nums))
print(all(n % 2 == 1 for n in nums))
print(any(n % 2 == 1 and n > 5 for n in nums))
False True True
Первая строка: чётных нет — False. Вторая: все три нечётные — True. Третья: нечётное больше пяти есть (семь и девять) — True. Обратите внимание на третью строку: условие с and проверяется для каждого элемента целиком, и any остановится на первом подходящем — на семёрке, не дойдя до девятки.
matrix = [[1, 2], [0, 4]]
print(all(all(row) for row in matrix))
print(any(all(row) for row in matrix))
False True
Вложенный any: для каждой строки спрашиваем all — все ли её числа ненулевые. Ответ True есть (строка [1, 2] целиком ненулевая). А вот all(all(row) ...) — «все строки целиком ненулевые» — даёт False: во второй строке стоит ноль, который Python считает ложным. Единица истинна, а ноль — нет, хотя оба это числа.
Замена флага: три поколения кода
Один и тот же вопрос «есть ли плохой элемент» в разное время писался по-разному. Первое поколение — цикл с флагом: завели переменную, меняли её в теле, проверяли после. Второе — цикл с флагом и break: то же, но с досрочным выходом. Третье — одна строка с any.
marks = [4, 2, 5, 3]
has_bad = False
for m in marks:
if m == 2:
has_bad = True
break
print('вручную:', has_bad)
print('через any:', any(m == 2 for m in marks))
вручную: True через any: True
Два ответа совпадают, но видны два разных уровня. Цикл с флагом — это пять строк ради одного слова True или False; any делает то же самое в одну. Если вы пишете цикл и в конце проверяете булеву переменную, задайте себе вопрос: что мешает написать это одной строкой? Обычно ответа нет.
marks = [4, 5, 2, 5]
ok = True
for m in marks:
if m < 3:
ok = False
print(ok)
print(all(m >= 3 for m in marks))
False False
Здесь разница видна в самом коде. Ручной вариант обходит весь список и на каждой плохой оценке переставляет флаг; all делает то же самое, но прекращает работу на первом нарушителе. На списке из двух тысяч оценок, где первая плохая стоит в начале, all проверит один элемент, а цикл — две тысячи.
Проверка через функцию
Когда условие сложное, его лучше вынести в отдельную функцию, а в any передать её вызов. Читается это как «есть ли элемент, который проходит проверку» — и правило живёт в одном месте, а не размазано по генератору.
def is_ok(mark):
return mark >= 3 and mark <= 5
marks = [4, 2, 5, 6]
print(any(is_ok(m) for m in marks))
print(all(is_ok(m) for m in marks))
True False
Четвёрка проходит проверку — any отвечает True. Но шестёрка выше пяти и двойка ниже трёх, так что all отвечает False. Такое разделение удобно, когда правило сложное или его нужно переиспользовать: правило описано один раз, а any и all просто спрашивают.
words = ['cat', 'dog', 'bird']
print(any(len(w) > 3 for w in words))
print(all(len(w) > 3 for w in words))
True False
Длина больше трёх — подходит bird, поэтому any отвечает True. Но cat и dog короче, так что all отвечает False. Никакой магии: внутри генератора стоит обычное выражение, а any и all лишь спрашивают, истинно ли оно хотя бы раз или каждый раз.
- валидация формы:
all(v != '' for v in form.values())— можно ли отправлять; - проверка логов:
any('ошибка' in line for line in log)— случилось ли что-то; - страховка перед дорогой работой:
if any(...)— запускать ли расчёт вообще; - сложное правило: вынести в функцию и звать её в генераторе;
- счёт подходящих:
sum(1 for x in xs if cond)— сколько прошло.
| Вопрос | Ручной цикл | Функция |
|---|---|---|
| Хотя бы один подходит? | флаг + for + break | any(условие for x in данные) |
| Все подходят? | флаг без переворотов | all(условие for x in данные) |
| Пустые данные | зависит от флага | any — False, all — True |
- валидация:
all(поле != '' for поле in форма)— можно ли отправлять; - тревога:
any(ошибка in строка for строка in лог)— случилось ли что-то; - быстрая проверка перед дорогой работой:
if any(...)— запускать ли расчёт.
any([True, False]) # по готовому списку значений
any(m == 2 for m in marks) # по генератору с условием
Сначала предскажи ответ в голове — это главный навык программиста.
print(any([0, 0]))
print(all([1, 2, 3]))
nums = [4, 6, 9]
print(any(n % 2 == 0 for n in nums))
words = ['', 'ok']
print(all(w for w in words))
print(any(w for w in words))
1. Что вернёт any([0, '', 7])?
2. На какой вопрос отвечает all(m >= 3 for m in marks)?
3. Что вернёт all([])?
4. Что такое короткое замыкание any?
5. Чем any(m == 2 for m in marks) отличается от any(marks)?
6. Как одной функцией узнать, сколько элементов прошло проверку?
7. Что проверит all(all(row) for row in matrix)?
8. Что произойдёт, если заменить all(m >= 3 for m in marks) на all(marks)?
Дан список temps = [12, 15, 3, 17]. С помощью any проверь, есть ли температура ниже 10 градусов, с помощью all — все ли температуры выше 5. Выведи оба ответа.
Что делает any в Python?
Проверяет, есть ли в последовательности хотя бы один истинный элемент, и возвращает True или False. С генератором any(m == 2 for m in marks) отвечает на вопрос «есть ли хоть одна двойка» и останавливается на первом совпадении.
Урок 12: генератор спискаЧем all отличается от any?
all требует истинности всех элементов сразу и даёт False от первого нарушителя, any достаточно одного подходящего элемента. На пустой последовательности any отвечает False, all — True.
Что вернёт all для пустого списка?
True: в пустом списке нет элементов, которые ломают условие «все». Логика такая: нарушителей не найдено, проверка пройдена. Если пустой список должен означать отказ, добавьте отдельную проверку длины.
Как проверить, что все элементы списка равны числу?
Записать сравнение в генератор: all(x == 5 for x in xs). Условие вычисляется для каждого элемента, any/all сами организуют цикл и досрочную остановку. Пустой список такую проверку пройдёт — помните про это.
Как посчитать, сколько элементов списка проходят проверку?
Через sum с генератором: sum(1 for x in xs if cond). В Python True равен единице и False равен нулю, поэтому sum считает успешные проверки. Надёжнее, чем sum по сырым значениям, если в списке лежат не булевы числа.
Урок 11: счётчики и аккумуляторыКак проверить словарь: заполнены ли все поля формы?
Обойти значения и проверить, что пустых нет: all(v != '' for v in form.values()). Если обойти сам словарь, проверятся ключи, а не содержимое полей — ключи у формы всегда непустые, и проверка пройдёт, даже когда форма пустая.
Заменяют ли any и all цикл с булевым флагом?
Для чистых вопросов «есть ли» и «все ли» — да: any(условие for ...) и all(условие for ...) делают то же самое короче и быстрее, заодно с досрочной остановкой. Флаг остаётся нужен, когда из цикла нужен сам найденный элемент, а не только ответ.
Понравился урок? Сошлитесь на него
«Функция any возвращает True, если условие выполнилось хотя бы для одного элемента, а all — если для всех без исключения.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Циклы · Урок 9
else у циклов в Python: поиск без флагов
У циклов for и while есть собственный else: он срабатывает, если перебор дошёл до конца без break. Поиск «нашли или нет» — в один заход и без флагов.
Циклы · Урок 11
Счётчики и аккумуляторы в циклах Python
Сумма чека, число совпадений, лучший результат: переменная, объявленная до цикла и копящая значения внутри, — приём старше языков. Разбираем счётчики, суммы, максимумы и их ловушки.
Циклы · Урок 12
Генератор списка в Python: цикл в одну строку
Цикл сбора списка — из трёх строк в одну: выражение, for, условие. Разбираем анатомию генератора списка, фильтр через if, превращение через if-else и границу, за которой однострочник вредит.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Функции · Урок 7
Функция map в Python: обработка списка
map применяет функцию к каждому элементу списка одной строкой. Разбираем ленивый итератор, обёртку list() и правило выбора между map и циклом.
map вместо цикла python
json · Урок 10
Обход данных: циклы по JSON-спискам
for по списку словарей, извлечение полей, суммирование выручки и list comprehension — превращаем выгрузку заказов в отчёт.
python цикл по jsonподсчёт элементов json python
Циклы · Урок 1
Цикл for в Python: первый цикл
Первый цикл for: компьютер повторяет одну строку за вас. Перебираем список, разбираем переменную цикла и тело с отступами — и видим, зачем цикл вместо копипасты.
цикл for pythonpython цикл for