«Проще просить прощения, чем разрешения». Проверка наличия следующего элемента у итератора не требует разрешения. Существуют ситуации, в которых вы хотите проверить наличие следующего элемента, не потребляя его. Я бы принял решение try catch, если бы был unnext()метод, чтобы вернуть первый элемент после того, как я проверил его существование, вызвав его next().
Джорджио
15
@ Джорджио, нет способа узнать, существует ли другой элемент без выполнения кода, который его генерирует (вы не знаете, будет ли работать генератор yieldили нет). Конечно, нетрудно написать адаптер, который хранит результат, next()а также предоставляет has_next()и move_next().
Авакар
5
Эта же идея может быть использована для реализации hasNext()метода (для создания, кэширования и возврата true при успехе или возврата false при сбое). Тогда и то hasNext()и другое next()будет зависеть от общего базового getNext()метода и кэшируемого элемента. Я действительно не понимаю, почему next()не должно быть в стандартной библиотеке, если это так легко реализовать адаптер, который обеспечивает его.
Джорджио
3
@LarsH: Вы имеете в виду, например, итератор, который читает из файла, который можно изменить во время чтения из него? Я согласен, что это может быть проблемой (которая затрагивает любую библиотеку, предоставляющую метод next()и hasNext()метод, а не только гипотетическую библиотеку Python). Так что да, next()и hasNext()становится сложно, если содержимое сканируемого потока зависит от того, когда элементы читаются.
Джорджио
239
Есть альтернатива StopIterationс помощью next(iterator, default_value).
Например:
>>> a = iter('hi')>>>print next(a,None)
h
>>>print next(a,None)
i
>>>print next(a,None)None
Таким образом, вы можете обнаружить Noneили другое заранее заданное значение для конца итератора, если вы не хотите использовать метод исключения.
если вы используете None в качестве «стража», лучше всего быть уверенным, что у вашего итератора нет None. Вы также можете сделать sentinel = object()и next(iterator, sentinel)и проверить с is.
Сам Boosalis
1
После @samboosalis я бы предпочел использовать встроенный unittest.mock.sentinelобъект, который позволяет вам написать явное, next(a, sentinel.END_OF_ITERATION)а затемif next(...) == sentinel.END_OF_ITERATION
ClementWalter
это красивее, чем исключение
datdinhquoc
Проблема в том, что таким образом вы также ПОТРЕБЛЯЕТЕ следующее значение от итератора. hasNext в Java не использует следующее значение.
Алан Францони
40
Если вам действительно нужно в has-nextфункциональности (потому что вы просто верно расшифровывать алгоритм от эталонной реализации в Java, скажем, или потому , что вы пишете прототип , который будет нужно быть легко расшифрованы в Java , когда она будет закончена), это легко получить это с небольшим классом обертки. Например:
class hn_wrapper(object):def __init__(self, it):
self.it = iter(it)
self._hasnext =Nonedef __iter__(self):return self
def next(self):if self._hasnext:
result = self._thenext
else:
result = next(self.it)
self._hasnext =Nonereturn result
def hasnext(self):if self._hasnext isNone:try: self._thenext = next(self.it)exceptStopIteration: self._hasnext =Falseelse: self._hasnext =Truereturn self._hasnext
теперь что-то вроде
x = hn_wrapper('ciao')while x.hasnext():print next(x)
излучает
c
i
a
o
как требуется.
Обратите внимание, что использование next(sel.it)в качестве встроенного требует Python 2.6 или выше; если вы используете более старую версию Python, используйте self.it.next()вместо этого (и аналогично для next(x)примера использования). [[Вы можете разумно думать, что эта заметка является излишней, поскольку Python 2.6 существует уже более года - но чаще, когда я использую функции Python 2.6 в ответе, некоторые комментаторы или другие считают необходимым указать на это что это 2,6 функции, поэтому я пытаюсь предупредить такие комментарии на этот раз ;-)]]
«добросовестная расшифровка алгоритма из эталонной реализации в Java» - худшая причина, по которой нужен has_nextметод. Дизайн Python делает невозможным, скажем, использование filterдля проверки, содержит ли массив элемент, соответствующий данному предикату. Высокомерие и близорукость сообщества Python ошеломляют.
Джонатан Каст
хороший ответ, я копирую это для иллюстрации некоторого шаблона проектирования, взятого из кода Java
madtyn
Я с Python3, и этот код дает мнеTypeError: iter() returned non-iterator
madtyn
1
@JonathanCast не уверен, что я следую. В Python вы обычно используете mapи anyвместо filter, но вы можете использовать SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINELили забыть SENTINELи просто использовать try: exceptи поймать StopIteration.
juanpa.arrivillaga
13
В дополнение ко всем упоминаниям StopIteration цикл Python for просто делает то, что вы хотите:
>>> it = iter("hello")>>>for i in it:...print i
...
h
e
l
l
o
Я всегда задавался вопросом, почему в Python есть все эти методы __ xxx __? Они кажутся такими уродливыми.
мП
6
Законный вопрос! Обычно это синтаксис методов, предоставляемых встроенной функцией (например, len, фактически вызывает len ). Такая встроенная функция не существует для length_hint, но на самом деле это ожидающее предложение (PEP424).
fulmicoton
1
@mP. эти функции есть, потому что они иногда необходимы. Они намеренно безобразны, потому что они рассматриваются как метод последней инстанции: если вы используете их, вы знаете, что делаете что-то непитонное и потенциально опасное (что также может перестать работать в любой момент).
Арне Бабенхаузерхайде
Вроде __init__и __main__? Имхо, это немного беспорядок, независимо от того, пытаетесь ли вы оправдать это.
user1363990
5
hasNextнесколько переводит на StopIterationисключение, например:
>>> it = iter("hello")>>> it.next()'h'>>> it.next()'e'>>> it.next()'l'>>> it.next()'l'>>> it.next()'o'>>> it.next()Traceback(most recent call last):File"<stdin>", line 1,in<module>StopIteration
Вариант использования, который привел меня к поиску этого заключается в следующем
def setfrom(self,f):"""Set from iterable f"""
fi = iter(f)for i in range(self.n):try:
x = next(fi)exceptStopIteration:
fi = iter(f)
x = next(fi)
self.a[i]= x
где hasnext () доступен, можно сделать
def setfrom(self,f):"""Set from iterable f"""
fi = iter(f)for i in range(self.n):ifnot hasnext(fi):
fi = iter(f)# restart
self.a[i]= next(fi)
который для меня чище. Очевидно, что вы можете обойти проблемы, определив служебные классы, но в результате вы получаете двадцать с лишним различных почти эквивалентных обходных путей, каждый из которых имеет свои причуды, и если вы хотите повторно использовать код, использующий разные обходные пути, вы должны либо иметь несколько почти эквивалентных в вашем приложении, или просто перебирать и переписывать код, чтобы использовать тот же подход. Принцип «сделай это один раз и сделай это хорошо» терпит неудачу.
Кроме того, сам итератор должен иметь внутреннюю проверку hasnext, чтобы увидеть, нужно ли ему вызывать исключение. Эта внутренняя проверка затем скрывается, поэтому ее необходимо протестировать, пытаясь получить элемент, перехватить исключение и запустить обработчик, если его сгенерировать. Это ненужное сокрытие ИМО.
Предложенный способ - StopIteration . Пожалуйста, посмотрите пример Фибоначчи с tutorialspoint
#!usr/bin/python3import sys
def fibonacci(n):#generator function
a, b, counter =0,1,0whileTrue:if(counter > n):returnyield a
a, b = b, a + b
counter +=1
f = fibonacci(5)#f is iterator objectwhileTrue:try:print(next(f), end=" ")exceptStopIteration:
sys.exit()
Способ, которым я решил свою проблему, заключается в том, чтобы до сих пор вести подсчет количества объектов, повторяемых. Я хотел перебрать множество, используя вызовы метода экземпляра. Так как я знал длину сета и количество посчитанных предметов, у меня был эффективный hasNextметод.
Конечно, пример игрушечный, но вы поняли идею. Это не будет работать в тех случаях, когда нет способа получить длину итерируемого, например, генератора и т. Д.
Ответы:
Нет, такого метода нет. Конец итерации обозначен исключением. Смотрите документацию .
источник
unnext()
метод, чтобы вернуть первый элемент после того, как я проверил его существование, вызвав егоnext()
.yield
или нет). Конечно, нетрудно написать адаптер, который хранит результат,next()
а также предоставляетhas_next()
иmove_next()
.hasNext()
метода (для создания, кэширования и возврата true при успехе или возврата false при сбое). Тогда и тоhasNext()
и другоеnext()
будет зависеть от общего базовогоgetNext()
метода и кэшируемого элемента. Я действительно не понимаю, почемуnext()
не должно быть в стандартной библиотеке, если это так легко реализовать адаптер, который обеспечивает его.next()
иhasNext()
метод, а не только гипотетическую библиотеку Python). Так что да,next()
иhasNext()
становится сложно, если содержимое сканируемого потока зависит от того, когда элементы читаются.Есть альтернатива
StopIteration
с помощьюnext(iterator, default_value)
.Например:
Таким образом, вы можете обнаружить
None
или другое заранее заданное значение для конца итератора, если вы не хотите использовать метод исключения.источник
sentinel = object()
иnext(iterator, sentinel)
и проверить сis
.unittest.mock.sentinel
объект, который позволяет вам написать явное,next(a, sentinel.END_OF_ITERATION)
а затемif next(...) == sentinel.END_OF_ITERATION
Если вам действительно нужно в
has-next
функциональности (потому что вы просто верно расшифровывать алгоритм от эталонной реализации в Java, скажем, или потому , что вы пишете прототип , который будет нужно быть легко расшифрованы в Java , когда она будет закончена), это легко получить это с небольшим классом обертки. Например:теперь что-то вроде
излучает
как требуется.
Обратите внимание, что использование
next(sel.it)
в качестве встроенного требует Python 2.6 или выше; если вы используете более старую версию Python, используйтеself.it.next()
вместо этого (и аналогично дляnext(x)
примера использования). [[Вы можете разумно думать, что эта заметка является излишней, поскольку Python 2.6 существует уже более года - но чаще, когда я использую функции Python 2.6 в ответе, некоторые комментаторы или другие считают необходимым указать на это что это 2,6 функции, поэтому я пытаюсь предупредить такие комментарии на этот раз ;-)]]источник
has_next
метод. Дизайн Python делает невозможным, скажем, использованиеfilter
для проверки, содержит ли массив элемент, соответствующий данному предикату. Высокомерие и близорукость сообщества Python ошеломляют.TypeError: iter() returned non-iterator
map
иany
вместоfilter
, но вы можете использоватьSENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL
или забытьSENTINEL
и просто использоватьtry: except
и пойматьStopIteration
.В дополнение ко всем упоминаниям StopIteration цикл Python for просто делает то, что вы хотите:
источник
Попробуйте метод __length_hint __ () из любого объекта итератора:
источник
__init__
и__main__
? Имхо, это немного беспорядок, независимо от того, пытаетесь ли вы оправдать это.hasNext
несколько переводит наStopIteration
исключение, например:StopIteration
документы: http://docs.python.org/library/exceptions.html#exceptions.StopIterationисточник
Вы можете
tee
использовать итераторitertools.tee
и проверить егоStopIteration
на итераторе teed.источник
Нет. Наиболее похожая концепция, скорее всего, является исключением StopIteration.
источник
Я полагаю, что в python просто есть next () и, согласно документу, он выдает исключение, если больше нет элементов.
http://docs.python.org/library/stdtypes.html#iterator-types
источник
Вариант использования, который привел меня к поиску этого заключается в следующем
где hasnext () доступен, можно сделать
который для меня чище. Очевидно, что вы можете обойти проблемы, определив служебные классы, но в результате вы получаете двадцать с лишним различных почти эквивалентных обходных путей, каждый из которых имеет свои причуды, и если вы хотите повторно использовать код, использующий разные обходные пути, вы должны либо иметь несколько почти эквивалентных в вашем приложении, или просто перебирать и переписывать код, чтобы использовать тот же подход. Принцип «сделай это один раз и сделай это хорошо» терпит неудачу.
Кроме того, сам итератор должен иметь внутреннюю проверку hasnext, чтобы увидеть, нужно ли ему вызывать исключение. Эта внутренняя проверка затем скрывается, поэтому ее необходимо протестировать, пытаясь получить элемент, перехватить исключение и запустить обработчик, если его сгенерировать. Это ненужное сокрытие ИМО.
источник
Предложенный способ - StopIteration . Пожалуйста, посмотрите пример Фибоначчи с tutorialspoint
источник
Способ, которым я решил свою проблему, заключается в том, чтобы до сих пор вести подсчет количества объектов, повторяемых. Я хотел перебрать множество, используя вызовы метода экземпляра. Так как я знал длину сета и количество посчитанных предметов, у меня был эффективный
hasNext
метод.Простая версия моего кода:
Конечно, пример игрушечный, но вы поняли идею. Это не будет работать в тех случаях, когда нет способа получить длину итерируемого, например, генератора и т. Д.
источник