Часто в программах на Python требуется проверить, является ли хотя бы один элемент структуры данных истинным. Да, можно написать цикл для перебора итерируемого объекта и проверки того, является ли каждый элемент истинным или ложным. Но функция any() – более эффективный и питонический способ достижения того же результата.
В этом руководстве мы рассмотрим встроенную функцию any() в Python и покажем несколько примеров и вариантов использования этой функции.
Что делает функция any() в Python?
Функция any() является одной из встроенных функций Python. Она принимает итерируемый объект, например список или кортеж, и возвращает True, если хотя бы одно значение в этом объекте истинно. Истинное значение оценивается как True при приведении к булеву типу с помощью bool()
. Если все значения в итерируемом объекте являются ложными, any()
возвращает False:
print(any([True, False, False, True])) print(any([False, False, False, False])) print(any([0, 0, 5, 0]))
True False True
Итерируемый объект, которы передается в any()
, может содержать булевы значения или другие объекты (при приведении к булеву значению в любом случае все объекты оцениваются как True или False). В третьем примере список содержит четыре целых числа. Целое число 0 является ложным, но все ненулевые числа являются истинными.
Если итерируемый объект пуст, any()
возвращает False, поскольку в пустом объекте нет истинных значений:
print(any([])) # Вывод: # False
Как работает функция any()?
Встроенная функция any() принимает в качестве аргумента любой итерируемый объект. Итерируемый объект – это любая структура данных, которую Python может перебирать в цикле.
Рассмотрим следующий кортеж:
an_iterable = ("", 0.0, "DataCamp", False, [])
Этот кортеж содержит несколько объектов с разными типами. Некоторые из этих объектов являются ложными:
- пустая строка
""
- число с плавающей точкой
0.0
- булево значение
False
- пустой список
[]
Эти объекты являются ложными, поскольку при передаче в bool()
они оцениваются как False.
Непустая строка «DataCamp» является истинной.
Простой способ проверить, является ли хотя бы один элемент истинным, – использовать цикл for
:
def check_if_contains_truthy(data): output = False for item in data: if item: output = True return output print(check_if_contains_truthy(an_iterable)) # Вывод: # True
Однако это неэффективно, поскольку наша функция должна проверять только наличие хотя бы одного истинностного значения. После нахождения истинного значения ей не нужно продолжать проверку остальных элементов итерируемого объекта. Эту функцию можно модифицировать, чтобы она завершала работу, как только найдет первое истинное значение:
def check_if_contains_truthy(data): for item in data: if item: return True return False print(check_if_contains_truthy(an_iterable)) # Вывод: # True
Оператор return
останавливает выполнение функции. Поэтому, когда функция находит первое истинное значение, она возвращает True и не продолжает перебор итерируемого объекта. Функция возвращает False только в том случае, если в цикле for
перебираются все элементы переданного итерируемого объекта и ни один из них не является истинным.
Встроенная функция any() работает по аналогичной схеме и завершает работу, когда находит первое истинное значение. Такая ленивая оценка позволяет избежать лишних операций, что повышает производительность.
Функция any() – это более эффективная версия функции, показанной выше. Ее эффективность можно проверить с помощью функции timeit()
из модуля timeit
, которая измеряет, сколько времени Python требуется для выполнения предложения (англ. statement):
from timeit import timeit print("Execution time for 'check_if_contains_truthy()'") print( timeit( "check_if_contains_truthy(an_iterable)", number=10_000_000, globals=globals(), ) ) print("Execution time for 'any()'") print( timeit( "any(an_iterable)", number=10_000_000, globals=globals(), ) )
Execution time for 'check_if_contains_truthy()' 0.6335119580035098 Execution time for 'any()' 0.39488654200249584
Первым аргументом функции timeit()
является строка, содержащая предложение, которое нужно выполнить. Второй аргумент определяет частоту выполнения этого предложения. В этом примере оба предложения выполняются 10 000 000 раз, чтобы получить значимое время. Последний аргумент передает глобальные переменные функции timeit()
.
Функция any()
в Python работает быстрее, чем check_if_contains_truthy()
. Использование any()
для определения того, есть ли в итерируемом объекте хотя бы одно истинное значение, более питонично и эффективно, чем использование цикла for
.
Примеры использования any()
Давайте рассмотрим несколько примеров использования any()
в Python.
Проверка валидности пользовательского ввода
Рассмотрим ряд пользовательских данных, собранных в список или кортеж. Программе может понадобиться проверить, является ли хотя бы одно из введенных значений валидным, например, непустой строкой:
user_inputs = ["", "10.99", ""] if any(user_inputs): print("At least one valid input present") # Rest of code... else: print("There are no valid inputs") # Вывод: # At least one valid input present
Поскольку одна из строк не пуста, any()
возвращает True, и код в предложении if
выполняется.
Проверка существования хотя бы одного файла
Встроенная функция any() может использоваться для проверки существования в каталоге хотя бы одного файла из заданного списка имен файлов:
from pathlib import Path files = ["article.md", "use_any.py", "scratch.py", "test_file.txt"] cwd = Path.cwd() # Create a test file to test code Path("test_file.txt").write_text("This is a test file") if any(Path(file).exists() for file in files): print("At least one of the files exists") # Rest of code… else: print("None of the files exist") # Вывод: # At least one of the files exists
Код получает текущий рабочий каталог с помощью модуля pathlib
и функции Path.cwd()
. В рабочем каталоге создается файл test_file.txt, чтобы код можно было легко протестировать. Функция any() используется для проверки того, есть ли хотя бы одно из имен файлов в текущем рабочем каталоге.
Фильтрация элементов итерируемого объекта
Встроенную функцию any()
также можно использовать с генераторным выражением для фильтрации элементов. В этом примере any()
ищет в списке словарей хотя бы одну запись, представляющую человека, чей возраст меньше 18 лет:
records = [ {"name": "Sarah", "age": 23}, {"name": "Jake", "age": 30}, {"name": "Paul", "age": 17}, ] if any(record["age"] < 18 for record in records): print("There's at least one minor.") else: print("All records are adults.") # Вывод: # There's at least one minor.
Это генераторное выражение выдает True или False в зависимости от значения, соответствующего ключу "age"
каждого словаря. Генераторное выражение можно использовать в функции any()
, поскольку оно является итерируемым.
Функция any() и ленивые вычисления
Предыдущий пример также демонстрирует, что any()
оценивается лениво. Рассмотрим следующую модификацию списка словарей:
records = [ {"name": "Sarah", "age": 23}, {"name": "Jake", "age": 30}, {"name": "Paul", "age": 17}, {"name": "Jill"}, ] if any(record["age"] < 18 for record in records): print("There's at least one minor.") else: print("All records are adults.") # Вывод: # There's at least one minor.
Четвертый словарь в records
не содержит элемента с ключом "age"
. Однако код не выдает ошибку при попытке получить значение, соответствующее "age"
для этого элемента, поскольку any()
ранее уже нашла истинное значение. Функция завершает работу, когда встречает первое истинное значение.
А если словарь, в котором отсутствует ключ "age"
, будет стоять перед любыми элементами с возрастом меньше 18 лет, код выдаст ошибку KeyError:
records = [ {"name": "Jill"}, {"name": "Sarah", "age": 23}, {"name": "Jake", "age": 30}, {"name": "Paul", "age": 17}, ] if any(record["age"] < 18 for record in records): print("There's at least one minor.") else: print("All records are adults.")
Traceback (most recent call last): ... if any(record["age"] < 18 for record in records): ~~~~~^^^^^^ KeyError: 'age'
Этот пример призван продемонстрировать вычисления по короткой схеме (ленивую оценку) при использовании any()
в Python. Но если код не должен вызывать исключения для элементов без ключа "age"
, вместо доступа к значению словаря с использованием нотации квадратных скобок можно использовать метод .get()
со значением по умолчанию. Предложение if
можно заменить следующей версией, если по умолчанию предполагается, что люди, к которым относятся записи без "age"
, не являются несовершеннолетними:
if any(record.get("age", 18) < 18 for record in records): # ...
Если же код должен считать, что любая запись без "age"
предполагает возраст меньше 18, то и значение по умолчанию должно быть меньше 18.
Сравнение функций any() и all()
У функции any()
в Python есть компаньонка – all()
. Эта встроенная функция также принимает итерируемый объект и возвращает True, если все элементы переданного объекта истинны.
Рассмотрим пример с валидацией вводимых пользователем данных. Функция any()
полезна, если приложение требует хотя бы одно валидное значение. А all()
можно использовать, если все вводимые пользователем данные должны быть валидными:
user_inputs = ["", "10.99", ""] if any(user_inputs): print("At least one valid input present") # Rest of code... else: print("There are no valid inputs") if all(user_inputs): print("All inputs are valid") # Rest of code... else: print("Not all inputs are valid")
At least one valid input present Not all inputs are valid
Но если все строки в пользовательском вводе непустые, all()
возвращает True:
user_inputs = ["5.99", "10.99", "19.99"] # …
At least one valid input present All inputs are valid
Как и any()
, встроенная функция all()
оценивается лениво. Функция завершает работу, когда находит первое ложное значение.
Заключение
Функция any() в Python проверяет, является ли любой из элементов итерируемого объекта истинным. Она возвращает True, если хотя бы один элемент в итерируемом объекте является True или оценивается как True при приведении к булеву значению. Хотя тот же результат можно получить с помощью цикла, эта встроенная функция предлагает более читабельное и эффективное решение.
Перевод статьи “Python any() Function: Guide With Examples and Use Cases”.