Как использовать any() в Python

Оглавление

Как программист на Python, вы часто будете иметь дело с логическими значениями и условными операторами — иногда очень сложными. В таких ситуациях вам, возможно, придется положиться на инструменты, которые могут упростить логику и консолидировать информацию. К счастью, any() в Python есть такой инструмент. Он просматривает элементы в iterable и возвращает единственное значение, указывающее, является ли какой-либо элемент истинным в логическом контексте или истинным.

В этом уроке вы узнаете:

  • Как использовать any()
  • Как выбрать между any() и or

Давайте сразу перейдем к делу!

Как использовать any() в Python

Представьте, что вы пишете программу для отдела подбора персонала вашего работодателя. Возможно, вы захотите назначить собеседования с кандидатами, которые соответствуют любому из следующих критериев:

  1. Уже знаете Python
  2. Имеете пятилетний или более опыт работы разработчиком
  3. Иметь ученую степень

Одним из инструментов, который вы могли бы использовать для написания этого условного выражения, является or:

# recruit_developer.py
def schedule_interview(applicant):
    print(f"Scheduled interview with {applicant['name']}")

applicants = [
    {
        "name": "Devon Smith",
        "programming_languages": ["c++", "ada"],
        "years_of_experience": 1,
        "has_degree": False,
        "email_address": "devon@email.com",
    },
    {
        "name": "Susan Jones",
        "programming_languages": ["python", "javascript"],
        "years_of_experience": 2,
        "has_degree": False,
        "email_address": "susan@email.com",
    },
    {
        "name": "Sam Hughes",
        "programming_languages": ["java"],
        "years_of_experience": 4,
        "has_degree": True,
        "email_address": "sam@email.com",
    },
]
for applicant in applicants:
    knows_python = "python" in applicant["programming_languages"]
    experienced_dev = applicant["years_of_experience"] >= 5

    meets_criteria = (
        knows_python
        or experienced_dev
        or applicant["has_degree"]
    )
    if meets_criteria:
        schedule_interview(applicant)

В приведенном выше примере вы проверяете учетные данные каждого кандидата и назначаете собеседование, если кандидат соответствует любому из трех ваших критериев.

Технические подробности: Функции any() и or в Python не ограничиваются вычислением логических выражений. Вместо этого Python выполняет проверку истинностных значений для каждого аргумента, оценивая, является ли выражение истинным или ложным. Например, ненулевые целые значения считаются истинными, а нулевые - ложными:

>>> 1 or 0
1

В этом примере or вычислил ненулевое значение 1 как истинное, даже если оно не имеет типа Boolean. or вернул 1 и в этом не было необходимости оцените правдивость 0. Позже в этом руководстве вы узнаете больше о возвращаемом значении и оценке аргументов or.

Если вы выполните этот код, то увидите, что Сьюзен и Сэм пройдут собеседования:

$ python recruit_developer.py
Scheduled interview with Susan Jones
Scheduled interview with Sam Hughes

Причина, по которой программа решила назначить собеседования со Сьюзен и Сэмом, заключается в том, что Сьюзен уже знает Python, а у Сэма есть ученая степень. Обратите внимание, что каждый кандидат должен соответствовать только одному критерию.

Еще один способ оценить полномочия заявителей - использовать any(). Когда вы используете any() в Python, вы должны передать учетные данные кандидатов в качестве повторяемого аргумента:

for applicant in applicants:
    knows_python = "python" in applicant["programming_languages"]
    experienced_dev = applicant["years_of_experience"] >= 5

    credentials = (
        knows_python,
        experienced_dev,
        applicant["has_degree"],
    )
    if any(credentials):
        schedule_interview(applicant)

Когда вы используете any() в Python, имейте в виду, что вы можете передать любую итерацию в качестве аргумента:

>>> any([0, 0, 1, 0])
True

>>> any(set((True, False, True)))
True

>>> any(map(str.isdigit, "hello world"))
False

В каждом примере any() перебирает различные итерации Python, проверяя истинность каждого элемента, пока не найдет истинное значение или не проверит каждый элемент.

Примечание: В последнем примере используется встроенный в Python map(),, который возвращает итератор, в котором каждый элемент является результатом передачи следующего символа в строке в str.isdigit(). Это полезный способ использования any() для более сложных проверок.

Возможно, вам интересно, не является ли any() просто усовершенствованной версией or. В следующем разделе вы узнаете о различиях между этими инструментами.

Как отличить or от any()

В Python есть два основных различия между or и any():

  1. Синтаксис
  2. Возвращаемое значение

Во-первых, вы узнаете о том, как синтаксис влияет на удобство использования и читаемость каждого инструмента. Во-вторых, вы узнаете о типах значений, которые возвращает каждый инструмент. Знание этих различий поможет вам решить, какой инструмент лучше всего подходит для данной ситуации.

Синтаксис

or это оператор, поэтому он принимает два аргумента, по одному с каждой стороны:

>>> True or False
True

any(), с другой стороны, это функция, которая принимает один аргумент, набор объектов, которые она перебирает циклически для оценки достоверности:

>>> any((False, True))
True

Это различие в синтаксисе существенно, поскольку оно влияет на удобство использования и читаемость каждого инструмента. Например, если у вас есть iterable, вы можете передать его непосредственно в any(). Чтобы получить аналогичное поведение от or, вам нужно будет использовать цикл или функцию, подобную reduce():

>>> import functools
>>> functools.reduce(lambda x, y: x or y, (True, False, False))
True

В приведенном выше примере вы использовали reduce() для передачи итерационной переменной в качестве аргумента or. Это можно было бы сделать гораздо эффективнее с помощью any, который напрямую принимает итерируемые значения в качестве аргументов.

Чтобы проиллюстрировать еще один способ, которым синтаксис каждого инструмента влияет на его удобство использования, представьте, что вы хотите избежать тестирования условия, если любое предыдущее условие выполняется True:

def knows_python(applicant):
    print(f"Determining if {applicant['name']} knows Python...")
    return "python" in applicant["programming_languages"]

def is_local(applicant):
    print(f"Determine if {applicant['name']} lives near the office...")

should_interview = knows_python(applicant) or is_local(applicant)

Если выполнение is_local() занимает относительно много времени, то вы не хотите вызывать его, когда knows_python() уже вернуло True. Это называется отложенной оценкой, или оценкой с коротким замыканием. По умолчанию or оценивает условия лениво, в то время как any этого не делает.

В приведенном выше примере программе даже не нужно было бы определять, местная ли Сьюзан, потому что она уже подтвердила, что она знает Python. Этого достаточно, чтобы назначить собеседование. В этой ситуации наиболее эффективным подходом был бы ленивый вызов функций с помощью or.

Почему бы вместо этого не использовать any()? Выше вы узнали, что any() принимает iterable в качестве аргумента, а Python вычисляет условия в соответствии с типом iterable. Итак, если вы используете список, Python выполнит как knows_python(), так и is_local() во время создания этого списка перед вызовом any():

should_interview = any([knows_python(applicant), is_local(applicant)])

Здесь Python вызовет is_local() для каждого кандидата, даже для тех, кто знает Python. Поскольку выполнение is_local() займет много времени, а иногда и не требуется, это неэффективная реализация логики.

Существуют способы заставить функции Python вызывать их лениво, когда вы используете итераторы, например, создать итератор с помощью map() или использовать выражение генератора :

any((meets_criteria(applicant) for applicant in applicants))

В этом примере используется генераторное выражение для генерации логических значений, указывающих, соответствует ли кандидат критериям для собеседования. Как только кандидат соответствует критериям, any() возвращает True, не проверяя остальных кандидатов. Но имейте в виду, что подобные обходные пути также сопряжены с определенными проблемами и могут быть применимы не в каждой ситуации.

Самое важное, что нужно помнить, - это то, что синтаксическая разница между any() и or может повлиять на удобство их использования.

Синтаксис - не единственное отличие, влияющее на удобство использования этих инструментов. Далее давайте рассмотрим различные возвращаемые значения для any() и or и то, как они могут повлиять на ваше решение о том, какой инструмент использовать.

Возвращаемое значение

В Python any() и or возвращают значения разных типов. any() возвращает логическое значение, которое указывает, найдено ли в итерируемом примере истинное значение:

>>> any((1, 0))
True

В этом примере any() нашел истинное значение (целое число 1), поэтому оно вернуло логическое значение True.

or, с другой стороны, возвращает первое найденное истинное значение, которое не обязательно будет логическим. Если истинных значений нет, то or возвращает последнее значение:

>>> 1 or 0
1

>>> None or 0
0

В первом примере or вычислил 1, что соответствует действительности, и вернул его без вычисления 0. Во втором примере None является ложным, поэтому or вычисляется следующим образом 0, что также является ложным. Но поскольку больше нет выражений для проверки, or возвращает последнее значение, 0.

Когда вы решаете, какой инструмент использовать, полезно подумать, хотите ли вы знать фактическое значение объекта или просто существует ли достоверное значение где-то в коллекции объектов.

Заключение

Поздравляем! Вы изучили все тонкости использования any() в Python и различия между any() и or. При более глубоком понимании этих двух инструментов вы будете хорошо подготовлены к выбору между ними в своем собственном коде.

Теперь вы знаете:

  • Как использовать any() в Python
  • Почему вы используете any() вместо or

Если вы хотите продолжить изучение условных выражений и использования таких инструментов, как or и any() в Python, вы можете ознакомиться со следующими ресурсами:

Back to Top