All any python: Page not found · GitHub Pages
Как использовать any() в Python — PYTHON
В этом уроке
Любой программист Python довольно часто имеет дело с булевскими выражениями и условными операторами, порой,. довольно сложными. В подобных ситуациях хотелось бы иметь инструменты, которые позволят упростить логику и консолидировать операции. К счастью, в Python есть такой инструмент и называется он any()
. Он просматривает итерируемые элементы и возвращает просто true, если присутствует указанное значение, или, что в логическом контексте означает правильно.
В этом уроке вы узнаете:
- Как использовать
any()
- В чём разница между
any()
иor
Поехали!
Как использовать any()
в Python
Представьте, что вы пишете программу для отдела по подбору персонала вашего работодателя. Возможно, вам придётся запланировать интервью с кандидатами, которые соответствуют любому из следующих требований:
- Знает Python
- Есть опыт работы от 5 лет и больше
- Есть учёная степень
Конечно, для этого можно использовать оператор 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": "*protected email*", }, { "name": "Susan Jones", "programming_languages": ["python", "javascript"], "years_of_experience": 2, "has_degree": False, "email_address": "*protected email*", }, { "name": "Sam Hughes", "programming_languages": ["java"], "years_of_experience": 4, "has_degree": True, "email_address": "*protected email*", }, ] 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)
В приведенном выше примере вы проверяете учетные данные каждого кандидата и назначаете собеседование, если кандидат отвечает хотя бы одному из трех названных критериев.
Если вы выполните этот код,то увидите, что Susan и Sam надо назначить интервью:
$ python recruit_developer.py Scheduled interview with Susan Jones Scheduled interview with Sam
Причина, по которой программа выбрала для интервью Susan и Sam, заключается в том, что Susan уже знает Python, а Sam есть ученую степень. Обратите внимание, каждый кандидат должен соответствовать только одному требованию для отбора.
Другой способ решения подобных задач — использование any()
. Когда в Python вы пишите any()
, то в качестве фактического аргумента должны передать ей итерируемый элемент:
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)
Имейте в виду, что когда в Python вы используете any()
, то можете передать ей любой итерируемый аргумент:
>>> 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()
:
- Синтаксис
- Возвращаемое значение
Для начала вы узнаете, как синтаксис влияет на удобство и надежность каждой конструкции. Во-вторых, вы узнаете типы возвращаемых значений этих конструкций. Знание различий поможет вам определиться, какая конструкция годится в каждой конкретной ситуации.
Синтаксис
or
есть operator, который требует по одному аргументу справа и слева.
>>> True or False True
С другой стороны, any()
есть функция у которой в качестве аргумента используется один итерируемый объект, который она перебирает до получения истинного значения:
>>> any((False, True)) True
Такая разница синтаксиса является значительной, поскольку влияет на удобство использования и чтения кода. Например, если у вас есть итератор, то его можно непосредственно передать в 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"Знает ли {applicant['name']} Python...") return "python" in applicant["programming_languages"] def is_local(applicant): print(f"Живёт ли {applicant['name']} рядом с офисом...") should_interview = knows_python(applicant) or is_local(applicant)
Так как is_local()
выполняется относительно медленно, то вам не надо её вызывать, если knows_python()
уже вернул True
, Такой вызов называется ленивой проверкой или коротким замыканием. По умолчанию or
является ленивой проверкой, а any
— нет.
В приведенном выше примере для Susen не надо выполнять проверу до конца, так как уже на первом шаге подтвеждается, что она знает Python. Этого вполне достаточно для назначения интервью. В этой ситуации наиболее эффективный подход — ленивая проверка с помощью or
.
Почему бы вместо этого используется any()
? Раньше вы узнали, что any()
принимает в качестве аргумента итератор, а Python оценивает условия в соответствии с типом итератора. Таким образом, если вы используете список, Python выполнит и know_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()
возвращает Boolean значение, которое показывает, нашла ли она истинное значение в итерираторе:
>>> any((1, 0)) True
В этом примере, any()
находит истинное значение (целое 1
), что приводит к логическому значению True
.
В отличии от any()
, or
возвращает первое найденное истинное значение, которое необязательно будет логическим. Если такого значения нет, то or
возвращает последнее значение:
>>> 1 or 0 1 >>> None or 0 0
В первом примере or
определил 1
и возвратил его 1
без значения 0
. Во втором примере None
является ложным, поэтому после or
определил 0
также ложным. Но поскольку дальше проверять нечего or
возвращает последнее значение, 0
.
Когда вы решаете, какую конструкцию использовать, полезно задуматься, хотите ли вы узнать фактическое значение объекта или просто существует ли истинное значение где-то в коллекции объектов.
Заключение
Поздравляем! Вы изучили все тонкости использования any()
в коде Python и различия между any()
и or
. Обладая более глубоким пониманием этих двух конструкций, вы, надеюсь, хорошо готовы к выбу между ними в своем собственном коде.
Теперь вы знаете:
- Как использовать
any()
в Python - Почему надо использовать
any()
вместоor
Если вы хотите углубиться в понимание конструкций, использующих or
и any()
в Python, рекоендую познакомиться с этими ресурсами:
Встроенные функции Python для работы с коллекциями (min, max, sum, all, any, enumerate)
max
- max(iterable, *[, key, default])
- max(arg1, arg2, *args[, key])
Функция возвращает максимальный элемент. Две версии функции отличаются аргументами: с итерируемым объектом и со списком аргументов.
print(max([3, 5, 8, 2])) # 8
print(max(3, 5, 8, 2)) # 8
| print(max([3, 5, 8, 2])) # 8 print(max(3, 5, 8, 2)) # 8 |
Если коллекция пустая возникнет исключение
print(max([], )) # ValueError
| print(max([], )) # ValueError |
Именованный аргумент default используется чтобы избежать исключения. Функция max возвращает default только если коллекция пустая:
print(max([], default=0)) # 0
print(max([2, 3], default=5)) # 3
| print(max([], default=0)) # 0 print(max([2, 3], default=5)) # 3 |
Порядок элементов изменяется аргументом key. Переданная в key функция применяется к каждому элементу. Результат функции используется для определения порядка элементов:
def neg(n):
return -n
print(max([3, 5, 8, 2], key=neg)) # 2
| def neg(n): return -n
print(max([3, 5, 8, 2], key=neg)) # 2 |
min
- min(iterable, *[, key, default])
- min(arg1, arg2, *args[, key])
Возвращает минимальный элемент. Две версии функции отличаются аргументами: с итерируемым объектом и со списком аргументов.
print(min([3, 5, 8, 2])) # 2
print(min(3, 5, 8, 2)) # 2
| print(min([3, 5, 8, 2])) # 2 print(min(3, 5, 8, 2)) # 2 |
Если коллекция пустая возникнет исключение
print(min([], )) # ValueError
| print(min([], )) # ValueError |
Именованный аргумент default используется чтобы избежать исключения. Функция min возвращает default только если коллекция пустая:
print(min([], default=0)) # 0
print(min([2], default=0)) # 2
| print(min([], default=0)) # 0 print(min([2], default=0)) # 2 |
Порядок элементов изменяется аргументом key. Переданная в key функция применяется к каждому элементу. Результат функции используется для определения порядка элементов:
def neg(n):
return -n
print(min([3, 5, 8, 2], key=neg)) # 8
| def neg(n): return -n
print(min([3, 5, 8, 2], key=neg)) # 8 |
sum(iterable, /, start=0)
Возвращает сумму элементов iterable:
print(sum([1, 2, 3])) # 6
print(sum([0.2, 0.3, 0.5])) # 1.0
print(sum([])) # 0
| print(sum([1, 2, 3])) # 6 print(sum([0.2, 0.3, 0.5])) # 1.0 print(sum([])) # 0 |
Необязательный аргумент start задаёт начальное значение:
print(sum([1, 2, 3], start= 2)) # 8
print(sum([], start= 2)) # 2
| print(sum([1, 2, 3], start= 2)) # 8 print(sum([], start= 2)) # 2 |
all(iterable)
Возвращает True если все элементы iterable равны True:
print(all([True, True, True])) # True
print(all([True, False, True])) # False
print(all(map(lambda x: x % 2 == 0, [2, 4, 6, 8]))) # True
| print(all([True, True, True])) # True print(all([True, False, True])) # False
print(all(map(lambda x: x % 2 == 0, [2, 4, 6, 8]))) # True |
Другие типы данных преобразуются к bool:
print(all([1, 2, 3])) # True
print(all([1, 2, 0])) # False
print(all([[1], []])) # False
| print(all([1, 2, 3])) # True print(all([1, 2, 0])) # False print(all([[1], []])) # False |
Если iterable пустой, то функция вернёт True:
Python Tips, Tricks, and Hacks (часть 2) / Хабр
Содержание
Списки. Свёртка списка (reduce). Прохождение по списку (range, xrange и enumerate). Проверка всех элементов списка на выполнение условия (all и any). Группировка элементов нескольких списков (zip). Еще несколько операторов для работы со списками. Продвинутые логические операции с типом set.
Словари. Создание словаря с помощью именованных аргументов. Преобразование словаря в список и обратно. «Dictionary Comprehensions».
2 Списки
2.2 Свёртка списка
К сожалению, нельзя написать программу только с помощью генераторов списков. (Я шучу… конечно, можно.) Они могут отображать и фильтровать, но нет простого способа для свертки списка. Под этим понятием я подразумеваю применение функции к первым двум элементам списка, а затем к получившемуся результату и следующему элементу, и так до конца списка. Можно реализовать это через цикл for:
Copy Source | Copy HTML
numbers = [1,2,3,4,5]
result = 1
for number in numbers:
result *= number
# result = 120
А можно воспользоваться встроенной функцией reduce, принимающей в качестве аргументов функцию от двух параметров и список:
Copy Source | Copy HTML
numbers = [1,2,3,4,5]
result = reduce(lambda a,b: a*b, numbers)
# result = 120
Не так красиво, как генераторы списков, но короче обычного цикла. Стоит запомнить этот способ.
2.3 Прохождение по списку: range, xrange и enumerate
Помните, как в языке C для цикла for вы использовали переменную-счетчик вместо элементов списка? Возможно, вы уже знаете, как имитировать это поведение в Python с помощью range и xrange. Передавая число value функции range, мы получим список, содержащий элементы от 0 до value-1 включительно. Другими словами, range возвращает индексы списка указанной длины. xrange действует похоже, но более эффективно, не загружая весь список в память целиком.
Copy Source | Copy HTML
strings = ['a', 'b', 'c', 'd', 'e']
for index in xrange(len(strings)):
print index,
# печатает "0 1 2 3 4"
Проблема в том, что обычно вам всё равно нужны элементы списка. Что толку от индексов без них? В Python есть потрясающая встроенная функция enumerate, которая воозвращает итератор для пар индекс → значение:
Copy Source | Copy HTML
strings = ['a', 'b', 'c', 'd', 'e']
for index, string in enumerate(strings):
print index, string,
# печатает "0 a 1 b 2 c 3 d 4 e"
Еще один плюс состоит в том, что enumerate выглядит более читаемо, чем xrange(len()). Поэтому range и xrange полезны, наверно, только для создания списка с нуля, а не на основе других данных.
2.4 Проверка всех элементов списка на выполнение условия
Допустим, нам надо проверить, выполняется ли условие хотя бы для одного элемента. До Python 2.5 можно было писать так:
Copy Source | Copy HTML
numbers = [1,10,100,1000,10000]
if [number for number in numbers if number < 10]:
print 'At least one element is over 10'
# Результат: "At least one element is over 10"
<source>
Если ни один из элементов не удовлетворяет условию, генератор создаст пустой список, который считается false. В противном случае будет создан непустой список, который приводится к true. Строго говоря, не нужно проверять все элементы, достаточно остановиться после первого элемента, удовлетворающего условию. Поэтому предыдущий пример менее эффективен и может быть выбран только в том случае, если вы не можете использовать Python 2.5, но хотите уместить всю логику в одно выражение.
С помощью встроенной функции any, введенной в Python 2.5, вы можете решить эту задачу более красиво и эффективно. Функция any прервется и вернет True, как только найдет элемент, удовлетворяющий условию. Ниже я использую выражение-генератор, которое возвращает True или False для каждого элемента, и передаю его функции any. Генератор вычисляет только необходимые в данный момент значения, а any принимает их по очереди.
<source>
Copy Source | Copy HTML
numbers = [1,10,100,1000,10000]
if any(number < 10 for number in numbers):
print 'Success'
# Результат: "Success!"
Аналогично, может возникнуть задача проверки, что все элементы удовлетворяют условию. Без Python 2.5 придется писать так:
Copy Source | Copy HTML
numbers = [1,2,3,4,5,6,7,8,9]
if len(numbers) == len([number for number in numbers if number < 10]):
print 'Success!'
# Результат: "Success!"
Здесь мы фильтруем список и проверяем, уменьшилась ли его длина. Если нет, то все его элементы удовлетворяют условию. Опять же, без Python 2.5 это единственный способ уместить всю логику в одно выражение.
В Python 2.5 есть более простой путь — встроенная функция all. Легко догадаться, что она прекращает проверку после первого элемента, не удовлетворяющего условию. Эта функция работает абсолютно аналогично предыдущей.
Copy Source | Copy HTML
numbers = [1,2,3,4,5,6,7,8,9]
if all(number < 10 for number in numbers):
print 'Success!'
# Результат: "Success!"
2.5 Группировка элементов нескольких списков
Встроенная функция zip используется для сжимания нескольких списков в один. Она возвращает массив кортежей, причем n-й кортеж содержит n-е элементы всех массивов, переданных в качестве аргументов. Это тот случай, когда пример — лучшее объяснение:
Copy Source | Copy HTML
letters = ['a', 'b', 'c']
numbers = [1, 2, 3]
squares = [1, 4, 9]
zipped_list = zip(letters, numbers, squares)
# zipped_list = [('a', 1, 1), ('b', 2, 4), ('c', 3, 9)]
Эта вещь часто используется как итератор для цикла for, извлекающая три значения за одну итерацию («for letter, number, squares in zipped_list»).
2.6 Еще несколько операторов для работы со списками
Ниже перечислены встроенные функции, в качестве аргумента принимающие любой итерируемый объект.
max и min возвращают наибольший и наименьший элемент соответственно.
sum возвращает сумму всех элементов списка. Опциональный второй параметр задает начальную сумму (по умолчанию 0).
2.7 Продвинутые логические операции с типом set.
Я понимаю, что в разделе, посвященном спискам, не положено говорить о сетах (sets). Но пока я не использовал их, мне не хватало некоторых логических операций в списках. Сет отличается от списка тем, что его элементы уникальны и неупорядоченны. Над сетами также можно выполнять множество логических операций.
Довольно распространенная задача — убедиться, что элементы списка уникальны. Это просто, достаточно преобразовать его в сет и проверить, изменилась ли длина:
Copy Source | Copy HTML
numbers = [1,2,3,3,4,1]
set(numbers)
# возвращает set([1,2,3,4])
if len(numbers) == len(set(numbers)):
print 'List is unique!'
# не выводит ничего
Конечно, вы можете преобразовать сет обратно в список, но не забывайте, что порядок элементов мог не сохраниться. Больше информации об операциях с сетами вы найдете в документации.
3 Словари
3.1 Создание словаря с помощью именованных аргументов
Когда я начал изучать Python, я полностью пропустил альтернативный способ создания словаря. Если передать конструктору dict именованные аргументы, они будут добавлены в возращаемый словарь. Конечно, на его ключи накладываются те же ограничения, что и на имена переменных. Вот пример:
Copy Source | Copy HTML
dict(a=1, b=2, c=3)
# возвращает {'a': 1, 'b': 2, 'c': 3}
Этот способ немного очищает код, избавляя вас от летающих вокруг кавычек. Я часто использую его.
3.2 Преобразование словаря в список
Чтобы получить список ключей, достаточно привести словарь к типу list. Но лучше использовать .keys() для получения списка ключей или .iterkeys() для получения итератора. Если вам нужны значения, используйте .values() и .itervalues(). Но помните, что словари не упорядочены, поэтому полученные значения могут быть перемешаны любым мыслимым образом.
Чтобы получить и ключи, и значения в виде списка кортежей, можно использовать .items() или .iteritems(). Возможно, вы часто пользовались этим захватывающим методом:
Copy Source | Copy HTML
dictionary = {'a': 1, 'b': 2, 'c': 3}
dict_as_list = dictionary.items()
#dict_as_list = [('a', 1), ('b', 2), ('c', 3)]
3.3 Преобразование списка в словарь
Обратная операция — превращение списка, содержащего пары ключ-значение, в словарь — делается так же просто:
Copy Source | Copy HTML
dict_as_list = [['a', 1], ['b', 2], ['c', 3]]
dictionary = dict(dict_as_list)
# dictionary = {'a': 1, 'b': 2, 'c': 3}
Вы можете комбинировать методы, добавив именованные аргументы:
Copy Source | Copy HTML
dict_as_list = [['a', 1], ['b', 2], ['c', 3]]
dictionary = dict(dict_as_list, d=4, e=5)
# dictionary = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
Превращать списка и словари друг в друга довольно удобно. Но следующий совет просто потрясающий.
3.3 «Dictionary Comprehensions»
Хотя в Python нет встроенного генератора словарей, можно сделать нечто похожее ценой небольшого беспорядка в коде. Используем .iteritems() для превращения словаря в список, передадим его выражению-генератору или генератору списков, а затем преобразуем список обратно в словарь.
Допустим, у нас есть словарь пар name:email, а мы хотим получить словарь пар name:is_email_at_a_dot_com (проверить каждый адрес на вхождение подстроки .com):
Copy Source | Copy HTML
emails = {'Dick': '[email protected]', 'Jane': '[email protected]', 'Stou': '[email protected]'}
email_at_dotcom = dict( [name, '.com' in email] for name, email in emails.iteritems() )
# email_at_dotcom = {'Dick': True, 'Jane': True, 'Stou': False}
Конечно, необязательно начинать и заканчивать словарем, можно в некоторых местах использовать и списки.
Это чуть менее читабельно, чем строгие генераторы списков, но я считаю, что это лучше, чем большой цикл for.
Статья целиком в PDF
Функция’ any() ‘или’ all() ‘ в python — python
Есть ли способ проверить два условия? Например,
a=np.array([1,2,3,4,5,6,7,8])
if any(a != 0 and a!=1)==True:
do something
EDIT: ответ предоставлен. Нет необходимости в каких-либо дополнительных вводах. Овации
python
Поделиться
Источник
Soma Healthy
12 марта 2015 в 18:29
3 Ответа
2
Вам нужно использовать объект генератора или итерационный объект, содержащий логические значения. Приведенное ниже выражение генератора содержит только true и false, в зависимости от того, является ли элемент числом, отличным от единицы и нуля.
if any(i != 0 and i != 1 for i in a):
print "I'll do something here"
Проблема в том, что вы пытались проверить, не равен ли массив нулю и единице, таким образом, передавая одно булево, а не итеративное или генератор. Вы хотите проверить отдельные значения, а не сам массив.
Поделиться
Malik Brahimi
12 марта 2015 в 18:39
0
Numpy
-это перебор, а any()
-бесполезно. Вместо этого используйте Set
if set(arr) - set([1,2]):
do something
Поделиться
Abhijit
12 марта 2015 в 18:35
0
Если вы просто хотите выполнить какое-то действие для всех элементов a
, которые не являются (например) 0 или 1, Вы можете сначала отфильтровать массив:
for element in filter(lambda x: x != 0 and x != 1, array):
#dosomething with element
Или для более читаемой версии, если вы не привыкли к анонимным функциям:
def func(a):
return a != 0 and a != 1
for element in filter(func, array):
#dosomething with element
Поделиться
EvenLisle
12 марта 2015 в 18:36
Похожие вопросы:
any() all() функция в python
Напишите функцию isAllLettersUsed (word, required), которая принимает слово в качестве первого аргумента и возвращает True, если слово содержит все буквы, найденные во втором аргументе. Образцы…
any() функция в Python
Я новичок в Python и играл с ним, пока у меня не возникла проблема с функцией any() . Согласно библиотеке Python, код для него является: def any(iterable): for element in iterable: if element:…
Путаница с функциями all() и any()
Я изучаю python и испытываю некоторую путаницу с пониманием функций all() и any() : 1 in [0,2] #False. Correct. all([0,1]) in [0,2] #True. Why? 1 is not in [0,2] any([0,1]) in [0,2] #False. Why? 0…
Как именно работает функция python any()?
На странице python docs для any эквивалентный код функции any() задается как: def any(iterable): for element in iterable: if element: return True return False Как эта функция узнает, какой элемент я…
использование ключевых слов «all» и «any» в python дает неожиданный результат?
У меня есть следующий код для вычисления простых чисел def isPrime(n): if (n==2): return True elif n<=1 or n%2==0: return False else: for i in xrange(3,n/2, 2): if n%i: return False return True…
Понимание any()-all() в Python
Я немного знаком с Python, однако до сих пор не понимаю, как использовать all() и any() . Я пытаюсь решить одну проблему; 2520-это наименьшее число, которое можно разделить на каждое из чисел от 1…
Что такое эквивалент функций python any() и all() в JavaScript?
Python does имеет встроенные функции any() и all() , которые применяются к списку (массиву в JavaScript) следующим образом- any(): Return True if any element of the iterable is true. If the iterable…
Clojure эквивалентно функциям Python «any» и «all»?
Существуют ли встроенные функции в Clojure, подобные функциям any и all Python? Например, в Python, это all([True, 1, ‘non-empty string’]) == True .
Почему «yield from» не работает так, как ожидалось в all() или any()?
Сегодня я отлаживал странную проблему. Программа сложная, но я упростил рассматриваемую часть до нескольких строк, воспроизводящих странное поведение. В примере я тестирую генератор случайных чисел…
Каков ближайший эквивалент функции any/all Python в Swift?
В Python встроенные функции any и all возвращают true, если любой из элементов в iterable является true или если все элементы в iterable являются true, соответственно. Например: any([False, False,…
🔁 Как писать выразительные циклы на Python: разбираемся на примерах
Синтаксис оператора цикла в Python одновременно и прост, и не традиционен. По сравнению с C-подобными языками циклы в Python лишены общей трехступенчатой
структуры for (init, condition, increment)
. В большинстве случаев достаточно for <item> in <iterable>
. Цикл while
используется реже.
<condition>
Хотя синтаксис цикла
не так уж сложен, хороший цикл не всегда просто написать. В этой статье мы рассмотрим несколько подходов, позволяющих писать чистый код даже для самых сложных циклов на Python.
У всякого языка программирования есть более или менее удачные подходы решения одних и тех же задач. Представим, вы спросили кого-то, кто только изучает Python: «Как получить текущий индекс при обходе списка?». Ответ
может быть следующим:
index = 0
for name in names:
print(index, name)
index += 1
Хотя приведенный цикл верен, это решение не в стиле Python. Разработчик с трехлетним опытом предложит
такой код:
for i, name in enumerate(names):
print(i, name)
enumerate()
– это
встроенная функция Python, которая принимает итерируемый объект в качестве параметра, а
затем возвращает новый объект – генератор кортежей вида (текущий индекс, текущий элемент)
. Это лучший
способ для данного случая: используется более интуитивно понятный код, к тому же он и продуктивнее.
Копнем приведенный пример поглубже. Цикл for
состоит из
структуры for <item> in <iterable>
. Левая половина присваивает значение переменной item
. В правой половине находится итерируемый объект, в качестве которого мы использовали функцию enumerate()
. Это подводит нас к первой
рекомендации.
Использование декоратора для обработки итерируемых объектов может по-разному влиять на код цикла. Прекрасный пример – встроенный модуль itertools. Это набор инструментальных функций,
содержащий множество полезных итерируемых объектов. О самом модуле мы писали в статье «Итерируем правильно». В этом материале мы рассмотрим примеры использования функций модуля в практических задачах.
Используйте product() для компактности
Все мы знаем, что «плоский»
код лучше вложенного. Но иногда приходится
писать многоуровневые вложенные циклы:
def find_twelve(num_list1, num_list2, num_list3):
"""Находит все комбинации чисел из трех списков,
в сумме дающие 12"""
for num1 in num_list1:
for num2 in num_list2:
for num3 in num_list3:
if num1 + num2 + num3 == 12:
return num1, num2, num3
Чтобы оптимизировать такие циклы, выполняющие обход объектов, можно использовать функцию product()
. Функция принимает
несколько итерируемых объектов и создает их декартово произведение.
from itertools import product
def find_twelve2(num_list1, num_list2, num_list3):
for n1, n2, n3 in product(lst1, lst2, lst3):
if n1 + n2 + n3 == 12:
return n1, n2, n3
По сравнению с
предыдущим кодом, цикл, использующий product()
, нуждается только в одном
уровне вложенности. Код становится более лаконичным.
Используйте islice(), чтобы обрабатывать только часть объектов цикла
Рассмотрим файл с
заголовками постов Reddit следующего вида:
py-guide: Python guidebook, written for humans.
---
Python 3 Death Clock
---
Run any Python Script with an Alexa Voice Command
---
<...>
Между каждой парой
заголовков, присутствует разделитель ---
, а нам нужны только заголовки. Основываясь на том, что мы уже знаем о функции enumerate()
, можно отфильтровать разделители по нечетным номерам:
def parse_titles(filename):
"""Читаем имя статьи reddit из файла"""
with open(filename,'r') as fp:
for i, line in enumerate(fp):
# Опускаем разделитель
if i% 2 == 0;
yield line.strip()
Однако использование функции islice()
из библиотеки itertools позволяет изменить сам итерируемый объект и упростить код. Функция islice (seq, start, end, step)
имеет почти те же параметры, что оператор среза (list[start:stop:step])
. Установим значение параметра step в 2 (по умолчанию 1).
from itertools import islice
def parse_ttiles_v2(filename):
with open(filename, 'r') as fp:
# Устанавливаем step=2
# упускаем разделитель '---'
for line in islice(fp, 0, None, 2):
yield line.strip()
Используйте takewhile вместо break
Иногда необходимо определить,
надо ли закончить цикл в самом его начале. Например:
for user in users:
# При появлении первого неквалифицированного пользователя
# дальнейшая обработка не производится
if not is_qualified(user):
break
# Выполняем обработку ...
Для раннего прерывания циклов можно использовать функцию takewhile()
. Функция takewhile
проходит по всем объектам из
(predicate, iterable)iterable
и вызывает функцию предиката, передав
текущий объект в качестве аргумента, и проверяет
возвращаемый результат.
Если функция предиката возвращает True
, генерируется объект и цикл продолжается, в обратном случае цикл прерывается.
from itertools import takewhile
for user in takewhile(is_qualified, users):
# Выполняем обработку ...
В itertools есть и
другие интересные функции, которые можно использовать вместе с циклами:
- функция
chain()
позволяет сделать плоскими двухуровневые вложенные циклы; - функция
zip_longest()
может организовать цикл сразу по нескольким объектам.
Если вас интересуют другие функции, переходите за подробностями к
официальной документации или к упоминавшейся публикации.
Используйте генераторы для написания своего декоратора
Кроме функций itertools, мы можем использовать генераторы в сочетании с декораторами. Возьмем простой пример.
def sum_even_only(numbers):
"""Суммирует все четные числа"""
result = 0
for num in numbers:
if num % 2 == 0:
result += num
return result
Для фильтрации всех
нечетных чисел в теле цикла здесь используется дополнительный оператор if
. Но если конструкция встречается часто и мы хотим
упростить тело цикла, можно определить функцию-генератор для фильтрации
четных чисел:
def even_only(numbers):
for num in numbers:
if num% 2 == 0:
yield num
def sum_even_only_v2(numbers):
"""Суммирует все четные числа"""
result = 0
for num in even_only(numbers):
result += num
return result
После декорирования
переменной numbers
функцией even_only
, функции sum_even_only_v2
не приходится фильтровать четные номера – остается только просуммировать.
Примечание
Приведенная простая функция на самом деле искусственна. В реальном мире лучше использовать выражение генератора или списка: sum(num for num in numbers if num% 2 == 0)
.
Когда мы пишем новый блок с циклом, нам хочется вставить побольше кода, включая фильтрацию недопустимых элементов, предварительную
обработку данных, печать логов и т. д. Даже небольшие куски
кода, не принадлежащие к той же абстракции, могут быть замешаны в том же магическом котелке.
Для примера рассмотрим бизнес-сценарий на некоем веб-сайте, выполняемый каждые 30 дней. Задача скрипта – найти пользователей,
входивших в систему каждые выходные в течение месяца, и выслать им за это наградные баллы.
import time
import datetime
def award_active_users_in_last_30days():
"""Получаем всех юзеров, которые вошли в систему с 8 вечера до 10 вечера
в выходные дни в течение последних 30 дней и отправляем им бонусные баллы
"""
days = 30
for days_delta in range(days):
dt = datetime.date.today()-datetime.timedelta(days=days_delta)
# 5: Saturday, 6: Sunday
if dt.weekday() not in (5, 6):
continue
time_start = datetime.datetime(dt.year, dt.month, dt.day, 20, 0)
time_end = datetime.datetime(dt.year, dt.month, dt.day, 23, 0)
# Преобразование в unix timestamp, необходимую для последующих запросов ORM
ts_start = time.mktime(time_start.timetuple())
ts_end = time.mktime(time_end.timetuple())
# Опрашиваем юзеров и отправляем 1000 бонусных баллов
for record in LoginRecord.filter_by_range(ts_start, ts_end):
# Здесь можно добавить сложную логику
send_awarding_points(record.user_id, 1000)
Вышеупомянутая функция
состоит из двух уровней. Ответственность внешнего цикла заключается в
отслеживании времени посещения за последние 30 дней, и преобразовании его в
формат UNIX timestamp. Эти две метки времени
используются внутренним циклом для дальнейшей передачи.
Рассмотрев эти вещи внимательно, мы можем прийти к выводу, что все тело цикла посвящено двум совершенно не зависящим друг от друга задачам: выбор даты и подготовка метки времени и рассылки наградных баллов.
Как
справиться со сложными циклами
Каковы недостатки
такого кода? В один прекрасный день выяснилось, что некоторые пользователи не спят после полуночи по
выходным и сидят на сайте. Появилось новое требование: «отправить уведомление юзерам,
которые вошли в систему между 3:00 и 5:00 в выходные дни за последние 30 дней».
Легко понять, что
новая проверка очень похожа на описанную перед кодом. Но, если посмотреть на
тело цикла, станет ясно, что код не может быть использован повторно. Внутри цикла слишком тесно связаны друг с другом разные логики: «выбрать время» и «разослать наградные баллы».
Чтобы эффективно
использовать код повторно, нужно отсоединить часть функции, отвечающей за «выбор времени», от тела
цикла. И в этом нам поможет наш старый друг, функция-генератор.
Разделение тела цикла с помощью функции-генератора
Чтобы отвязать выбор времени от цикла, определим функцию-генератор gen_weekend_ts_ranges()
, которая используется для
генерации меток времени UNIX:
def gen_weekend_ts_ranges(days_ago, hour_start, hour_end):
"""Создаем временной диапазон суббота-воскресенье
и возвращаем его в виде UNIX timestamp.
"""
for days_delta in range(days_ago):
dt = datetime.date.today()-datetime.timedelta(days=days_delta)
# 5: Saturday, 6: Sunday
if dt.weekday() not in (5, 6):
continue
time_start = datetime.datetime(dt.year, dt.month, dt.day, hour_start, 0)
time_end = datetime.datetime(dt.year, dt.month, dt.day, hour_end, 0)
# Преобразование в unix timestamp, необходимое для последующих запросов ORM
ts_start = time.mktime(time_start.timetuple())
ts_end = time.mktime(time_end.timetuple())
yield ts_start, ts_end
С помощью новой функции-генератора старую задачу «разослать наградные баллы» и новую задачу «разослать уведомления»
можно реализовать повторным использованием одного и того же цикла:
def award_active_users_in_last_30days_v2():
"""Отправляет бонусные баллы"""
for ts_start, ts_end in gen_weekend_ts_ranges(30, hour_start=20, hour_end=23):
for record in LoginRecord.filter_by_range(ts_start, ts_end):
send_awarding_points(record.user_id, 1000)
В данной статье мы
сначала кратко пробежались по определению «правильного» кода циклов. Затем возникло первое предложение: использовать функции-декораторы для улучшения
производительности. В завершение на примере бизнес-сценария описали важность
«дробления» кода в цикле в зависимости от исполняемых этим кодом задач.
Кратко о некоторых
моментах:
- использование декораторов для изменения итерируемого объекта может улучшить код циклов;
- множество полезных функций, способных улучшить цикл содержит модуль itertools;
- используйте функции-генераторы для простого определения собственного декоратора;
- не забывайте разделять логику бизнес-задач при разрастании циклов;
- используйте функции-генераторы для разделения блоков кода в цикле, выполняющих разные задачи, чтобы повысить гибкость.
Библиотека
программиста надеется, что найдете эти подходы такими же полезными, как и мы.
Удачи в обучении!
Страница не найдена · GitHub Pages
Страница не найдена · GitHub Pages
Файл не найден
Сайт, настроенный по этому адресу, не
содержать запрошенный файл.
Если это ваш сайт, убедитесь, что регистр имени файла соответствует URL-адресу.
Для корневых URL (например, http://example.com/
) вы должны предоставить
index.html
файл.
Прочтите полную документацию
для получения дополнительной информации об использовании GitHub Pages .
.
Как работают все функции Python?
Переполнение стека
- Около
Продукты
- Для команд
Переполнение стека
Общественные вопросы и ответыПереполнение стека для команд
Где разработчики и технологи делятся частными знаниями с коллегамиВакансии
Программирование и связанные с ним технические возможности карьерного ростаТалант
Нанимайте технических специалистов и создавайте свой бренд работодателяРеклама
Обратитесь к разработчикам и технологам со всего мира- О компании
.
Python любой ()
Синтаксис any ()
:
любой (повторяемый)
Параметры функции any ()
Функция any ()
принимает итерацию (список, строку, словарь и т. Д.) В Python.
Значение, возвращаемое функцией any ()
Функция any ()
возвращает логическое значение:
-
Истинно
, если хотя бы один элемент итерации истинен -
Ложь
, если все элементы ложны или итерация пуста
Состояние | Возвращаемое значение |
---|---|
Все значения верны | Истинно |
Все значения неверны | Ложь |
Одно значение истинно (другие ложно) | Истинно |
Одно значение неверно (другие верны) | Истинно |
Пустой итерабельный | Ложь |
Пример 1: Использование any () в списках Python
# Верно, поскольку 1,3 и 4 (хотя бы один) верны
l = [1, 3, 4, 0]
печать (любой (l))
# False, поскольку оба значения False
l = [0, ложь]
печать (любой (l))
# Верно, поскольку 5 верно
l = [0, ложь, 5]
печать (любой (l))
# False, поскольку итерабельность пуста
l = []
печать (любая (l))
Выход
Верно Ложь Правда Ложь
Метод any ()
работает аналогичным образом для кортежей и наборов, подобных спискам.
Пример 2: Использование any () в строках Python
# По крайней мере, один (фактически все) элементы истинны
s = "Это хорошо"
печать (любые)
# 0 неверно
# '0' истинно, так как это строковый символ
s = '000'
печать (любые)
# False, поскольку итерируемый пустой
s = ''
печать (любые)
Выход
Верно Правда Ложь
Пример 3: Использование any () со словарями Python
В случае словарей, если все ключи (не значения) ложны или словарь пуст, any ()
возвращает False
.Если хотя бы один ключ верен, any ()
возвращает True
.
# 0 ложно
d = {0: 'False'}
печать (любой (d))
# 1 верно
d = {0: 'Ложь', 1: 'Верно'}
печать (любой (d))
# 0 и False ложны
d = {0: 'False', False: 0}
печать (любой (d))
# iterable пуст
d = {}
печать (любой (d))
# 0 неверно
# '0' истинно
d = {'0': 'Ложь'}
печать (любая (д))
Выход
Ложь Правда Ложь Ложь Правда
.
Python все ()
Синтаксис метода all ()
:
все (повторяется)
все () Параметры
all ()
метод принимает один параметр:
Возвращаемое значение от всех ()
all ()
метод возвращает:
- True — Если все элементы в итерации верны
- False — Если какой-либо элемент в итерируемом объекте имеет значение false
Когда | Возвращаемое значение |
---|---|
Все значения верны | Истинно |
Все значения неверны | Ложь |
Одно значение истинно (другие ложно) | Ложь |
Одно значение неверно (другие верны) | Ложь |
Пустой итерабельный | Истинно |
Пример 1. Как all () работает для списков?
# все значения верны
l = [1, 3, 4, 5]
печать (все (l))
# все значения false
l = [0, ложь]
печать (все (l))
# одно ложное значение
l = [1, 3, 4, 0]
печать (все (l))
# одно истинное значение
l = [0, ложь, 5]
печать (все (l))
# пустой итерируемый
l = []
печать (все (л))
Выход
Верно Ложь Ложь Ложь Правда
Метод any ()
работает аналогичным образом для кортежей и наборов, таких как списки.
Пример 2: Как all () работает со строками?
s = "Это хорошо"
печать (все (и))
# 0 неверно
# '0' истинно
s = '000'
печать (все)
s = ''
печать (все)
Выход
Верно Правда Правда
Пример 3: Как all () работает со словарями Python?
В случае словарей, если все ключи (не значения) верны или словарь пуст, all () возвращает True. В противном случае он возвращает false для всех остальных случаев..
с = {0: 'Ложь', 1: 'Ложь'}
печать (все)
s = {1: 'Истина', 2: 'Истина'}
печать (все)
s = {1: 'Истина', ложь: 0}
печать (все)
s = {}
печать (все)
# 0 неверно
# '0' истинно
s = {'0': 'Истина'}
печать (все)
Выход
Ложь Правда Ложь Правда Правда
.