Как обращаться с исчерпанным итератором?
При поиске Python Documentation я нашел эквивалентную реализацию Python для создания Pythons zip()
функция.
Вместо того, чтобы ловить StopIteration
исключение, которое сигнализирует о том, что больше нет элементов, созданных итератором , автор ) используйте оператор if
, чтобы проверить, была ли принятая форма значения по умолчанию next()
равна object()
( "sentinel
" ) и остановите генератор:
def zip(*iterables):
# zip('ABCD', 'xy') --> Ax By
sentinel = object()
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
elem = next(it, sentinel)
if elem is sentinel:
return
result.append(elem)
yield tuple(result)
Интересно, существует ли какая-либо разница между приложением исключения или выражением if
, используемым документами Python?
Или лучше, поскольку главный герой @hiro указал:
Что не так с использованием оператора try
, учитывая EAFP (проще просить прощения, чем разрешение) в Python?
def zip(*iterables):
# zip('ABCD', 'xy') --> Ax By
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
try:
elem = next(it)
except StopIteration:
return
result.append(elem)
yield tuple(result)
Также как Стоян Деков сказал: "Блок try/except чрезвычайно эффективен , если исключения не подняты. Фактически ловить исключение дорого". (см. документы для получения дополнительной информации)
Но исключение произойдет только один раз, а именно, как только итератор исчерпан. Таким образом, обработка исключений будет лучшим решением в этом случае?
Ответы
Ответ 1
Вы имеете в виду, в отличие от этого?
def zip2(*iterables):
# zip('ABCD', 'xy') --> Ax By
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
try:
elem = next(it)
except StopIteration:
return
result.append(elem)
yield tuple(result)
Интересный вопрос... я бы предпочел эту альтернативную версию, особенно учитывая EAFP (проще попросить прощения, чем разрешение.)
даже если try/except медленнее, чем оператор if; это происходит только один раз - как только первый итератор исчерпан.
возможно, стоит отметить, что это не фактическая реализация в python; просто реализация, эквивалентная реальной реализации.
ОБНОВЛЕНИЕ в соответствии с комментариями:
обратите внимание, что PEP 479 предлагает return
из генератора и не поднимать StopIteration
.
Ответ 2
Как правило, повышение исключений всегда считается дорогостоящей операцией на любом языке программирования. Есть много веб-сайтов для чтения, почему это так, и я не буду вдаваться в подробности о том, что он включает.
Из Документы Python.
Блок try/except чрезвычайно эффективен, если не возникает никаких исключений. На самом деле ловить исключение дорого.
Оба варианта использования if/else
и try/catch
имеют свои преимущества и недостатки в зависимости от ситуации.
- Например,
try/catch
используется в основном для случаев, когда исключение является редким событием (например, код будет почти во всех случаях).
- В вашем примере вы знаете, что цикл будет генерировать исключение каждый раз, когда он вызывается, что делает очень неэффективным использование
try/catch
Ответ 3
Когда вы видите эквивалентный код python в документах, цель такого кода легко понять. if
легко понять, а try/except
- конструкция более высокого уровня.
Функционально нет разницы. Разумеется, может быть небольшая, но, вероятно, незначительная разница.
Что касается реального кодирования, разные люди думают по-разному, поэтому используйте тот способ, который имеет для вас больше смысла. Время, когда LBYL и EAFP действительно имеют значение, - это когда условие гонки может существовать - и здесь нет такого условия.