ПрограммированиеBackend разработчик

Объясните, как работает встроенная функция any() в Python, для чего она используется, и в чем отличие её от all().

Проходите собеседования с ИИ помощником Hintsage

Ответ

Функция any() была введена в Python 2.5 для удобной проверки: есть ли хотя бы один истинный элемент в итерируемом объекте (например, список, кортеж, генератор). Она полезна, когда нужно проверить выполнение хотя бы одного условия из множества.

Исторически, без неё приходилось писать цикл с прерыванием по найденному элементу или же комбинировать map и reduce — это было громоздко и медленно. Основная проблема, которую решает any(), — лаконичность и читаемость такого рода проверок.

Решение — any() и all() работают с ленивой оценкой (останавливаются, как только найдут False или True соответственно). Важно понимать разницу: any() возвращает True при первом истинном элементе, all() — если все элементы истинны.

Пример кода:

nums = [0, 0, 3, 0] if any(nums): print('В списке есть ненулевой элемент')

Ключевые особенности:

  • Any() возвращает True, если хотя бы один элемент истинный, иначе False
  • All() возвращает True только если все элементы истинные
  • Работают с ленивой оценкой (корректно работают с бесконечными генераторами)

Вопросы с подвохом.

Что произойдет, если в качестве аргумента any() передать пустой список?

Any() вернет False. Это логично: в пустой последовательности нет ни одного истинного элемента.

Чем any() принципиально отличается от all()?

Any() проверяет наличие хотя бы одного истинного значения. All() проверяет истинность всех значений. Их результаты обратны друг другу лишь для строго пустых коллекций.

Можно ли использовать any() с генератором, который может быть бесконечным?

Да, можно, и именно благодаря ленивой оценке any остановится, как только встретит True. Если же генератор никогда не даст True, функция не закончится сама по себе.

def infinite_gen(): while True: yield 0 # any(infinite_gen()) — будет работать бесконечно, если нет условий выхода

Типовые ошибки и анти-паттерны

  • Путаница между any и all
  • Передача неитерируемого объекта (получим TypeError)
  • Попытка контролировать события в бесконечном генераторе без условий останова

Пример из жизни

Негативный кейс

Хочется проверить, что хотя бы одно значение не None:

values = [None, None, None] if any(values): do_something() # Никогда не сработает, если просто забыли, что None == False

Плюсы:

  • Использование any() делает код короче

Минусы:

  • Если набор никогда не содержит истинных значений, блок кода никогда не сработает

Позитивный кейс

Корректное применение — искать хотя бы одного пользователя старше 30:

users = [{'age': 25}, {'age': 35}] if any(u['age'] > 30 for u in users): print('Есть пользователь старше 30')

Плюсы:

  • Лаконично, читаемо, работает с любым итерируемым объектом

Минусы:

  • Неявно остановится при первом же True, что иногда требует явного комментирования логики