Хіба не було ітераторів Python hasNext
?
Хіба не було ітераторів Python hasNext
?
Відповіді:
Ні, такого методу немає. Кінець ітерації позначається винятком. Дивіться документацію .
unnext()
метод повернути перший елемент назад після того, як я перевірив його наявність, зателефонувавши next()
.
yield
чи ні). Звичайно, не важко написати адаптер, який зберігає результат next()
і надає has_next()
і move_next()
.
hasNext()
методу (виробляти, кешувати і повертати істину на успіх, або повертати помилкову помилку). Тоді і те, hasNext()
і next()
залежатиме від загального базового getNext()
методу та кешованого елемента. Я дійсно не бачу, чому next()
не має бути в стандартній бібліотеці, якщо це так просто реалізувати адаптер, який це забезпечує.
next()
та hasNext()
методу, а не лише гіпотетичної бібліотеки Python). Так, так, next()
і hasNext()
стає складно, якщо вміст потоку, який відсканується, залежить від того, коли елементи будуть прочитані.
Існує альтернатива StopIteration
використанню next(iterator, default_value)
.
Для прикладу:
>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None
Таким чином, ви можете виявити 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 , коли вона буде закінчена), це легко отримайте його з невеликим класом обгортки. Наприклад:
class hn_wrapper(object):
def __init__(self, it):
self.it = iter(it)
self._hasnext = None
def __iter__(self): return self
def next(self):
if self._hasnext:
result = self._thenext
else:
result = next(self.it)
self._hasnext = None
return result
def hasnext(self):
if self._hasnext is None:
try: self._thenext = next(self.it)
except StopIteration: self._hasnext = False
else: self._hasnext = True
return 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 функції, тому я намагаюся заздалегідь передбачити такі коментарі ;-)]]
has_next
метод. Дизайн Python унеможливлює, скажімо, використання filter
для перевірки, чи містить масив елемент, що відповідає заданому предикату. Зарозумілість та недалекоглядність спільноти Пітон є приголомшливою.
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" просто робить те, що ви хочете:
>>> it = iter("hello")
>>> for i in it:
... print i
...
h
e
l
l
o
Спробуйте метод __length_hint __ () з будь-якого об'єкта ітератора:
iter(...).__length_hint__() > 0
__init__
і __main__
? Імхо, це трохи безлад, незалежно від того, намагаєтеся ви виправдати це.
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
StopIteration
Документи: http://docs.python.org/library/exceptions.html#exceptions.StopIterationНі. Найбільш схожа концепція, швидше за все, є винятком StopIteration.
Я вважаю, що у python просто є next (), і згідно з doc, він викидає виняток, якщо немає більше елементів.
Випадок використання, який веде мене до пошуку цього, наступний
def setfrom(self,f):
"""Set from iterable f"""
fi = iter(f)
for i in range(self.n):
try:
x = next(fi)
except StopIteration:
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):
if not hasnext(fi):
fi = iter(f) # restart
self.a[i] = next(fi)
що для мене чистіше. Очевидно, що ви можете вирішити проблеми, визначивши класи утиліти, але що трапляється, це у вас розповсюдження двадцяти разових різних майже еквівалентних обхідних шляхів кожного з їх вигадками, і якщо ви хочете повторно використовувати код, який використовує різні обхідні шляхи, вам доведеться або мати кілька близьких до еквіваленту у вашій одній програмі, або обійти перебір та перезапис коду, щоб використовувати той самий підхід. Максим "зроби це один раз і зроби це добре" погано.
Крім того, сам ітератор повинен мати внутрішню перевірку "hasnext", щоб перевірити, чи потрібно підняти виняток. Потім ця внутрішня перевірка прихована так, що її потрібно перевірити, намагаючись дістати предмет, перехопивши виняток та запустивши обробник, якщо його кинули. Це зайве приховування ІМО.
Запропонований спосіб - StopIteration . Будь ласка, дивіться приклад Фібоначчі з підручника
#!usr/bin/python3
import sys
def fibonacci(n): #generator function
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(5) #f is iterator object
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
Те, як я вирішив свою проблему, - до цього часу вести підрахунок кількості повторених об'єктів. Я хотів перебрати набір за допомогою викликів методу екземпляра. Оскільки я знав тривалість набору та кількість підрахованих досі предметів, я фактично мавhasNext
метод.
Проста версія мого коду:
class Iterator:
# s is a string, say
def __init__(self, s):
self.s = set(list(s))
self.done = False
self.iter = iter(s)
self.charCount = 0
def next(self):
if self.done:
return None
self.char = next(self.iter)
self.charCount += 1
self.done = (self.charCount < len(self.s))
return self.char
def hasMore(self):
return not self.done
Звичайно, приклад - іграшковий, але ви отримуєте ідею. Це не спрацює у випадках, коли немає можливості отримати довжину ітерабельного, наприклад генератора тощо.