Haben Python-Iteratoren keine hasNext
Methode?
Haben Python-Iteratoren keine hasNext
Methode?
Antworten:
Nein, es gibt keine solche Methode. Das Ende der Iteration wird durch eine Ausnahme angezeigt. Siehe die Dokumentation .
unnext()
Methode gäbe , um das erste Element zurückzusetzen, nachdem ich durch Aufrufen überprüft habe, ob es existiert next()
.
yield
oder nicht). Es ist natürlich nicht schwierig, einen Adapter zu schreiben, der das Ergebnis von next()
und liefert has_next()
und liefert move_next()
.
hasNext()
Methode zu implementieren (um bei Erfolg true zu erzeugen, zwischenzuspeichern und zurückzugeben oder bei einem Fehler false zurückzugeben). Dann beides hasNext()
und next()
würde von einer gemeinsamen zugrunde liegenden getNext()
Methode und einem zwischengespeicherten Element abhängen . Ich verstehe wirklich nicht, warum next()
es nicht in der Standardbibliothek sein sollte, wenn es so einfach ist, einen Adapter zu implementieren, der es bereitstellt.
next()
und hasNext()
-methode auswirkt , nicht nur auf eine hypothetische Python-Bibliothek). Also ja, next()
und hasNext()
wird schwierig, wenn der Inhalt des gescannten Streams davon abhängt, wann Elemente gelesen werden.
Es gibt eine Alternative zur StopIteration
Verwendung next(iterator, default_value)
.
Zum Beispiel:
>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None
Sie können also einen None
oder einen anderen vordefinierten Wert für das Ende des Iterators erkennen, wenn Sie die Ausnahmemethode nicht möchten.
sentinel = object()
und next(iterator, sentinel)
und Test mit is
.
unittest.mock.sentinel
Objekt verwenden, mit dem Sie ein explizites next(a, sentinel.END_OF_ITERATION)
und dannif next(...) == sentinel.END_OF_ITERATION
Wenn Sie wirklich eine Funktionalität benötigenhas-next
(weil Sie beispielsweise nur einen Algorithmus aus einer Referenzimplementierung in Java originalgetreu transkribieren oder weil Sie einen Prototyp schreiben, der nach Abschluss einfach in Java transkribiert werden muss), ist dies einfach Erhalten Sie es mit einer kleinen Wrapper-Klasse. Beispielsweise:
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
jetzt so etwas wie
x = hn_wrapper('ciao')
while x.hasnext(): print next(x)
emittiert
c
i
a
o
nach Bedarf.
Beachten Sie, dass für die Verwendung next(sel.it)
als integriertes Programm Python 2.6 oder besser erforderlich ist. Wenn Sie eine ältere Version von Python verwenden, verwenden Sie self.it.next()
stattdessen (und ähnlich wie next(x)
im Beispiel). [[Sie könnten vernünftigerweise denken, dass dieser Hinweis überflüssig ist, da Python 2.6 bereits seit über einem Jahr verfügbar ist - aber meistens, wenn ich Python 2.6-Funktionen in einer Antwort verwende, fühlen sich einige Kommentatoren oder andere verpflichtet, darauf hinzuweisen dass es sich um 2.6-Features handelt, daher versuche ich, solchen Kommentaren einmal zuvorzukommen ;-)]]
has_next
Methode zu benötigen . Das Design von Python macht es beispielsweise unmöglich zu filter
überprüfen, ob ein Array ein Element enthält, das mit einem bestimmten Prädikat übereinstimmt. Die Arroganz und Kurzsichtigkeit der Python-Community ist atemberaubend.
TypeError: iter() returned non-iterator
map
und any
anstelle von verwenden filter
, aber Sie könnten a verwenden SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL
oder vergessen SENTINEL
und einfach das verwenden try: except
und abfangen StopIteration
.
Zusätzlich zu allen Erwähnungen von StopIteration macht die Python "for" -Schleife einfach das, was Sie wollen:
>>> it = iter("hello")
>>> for i in it:
... print i
...
h
e
l
l
o
Probieren Sie die Methode __length_hint __ () für jedes Iteratorobjekt aus:
iter(...).__length_hint__() > 0
__init__
und __main__
? Imho, es ist ein bisschen chaotisch, egal du versuchst es zu rechtfertigen.
hasNext
übersetzt etwas in die StopIteration
Ausnahme, zB:
>>> 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
Dokumente: http://docs.python.org/library/exceptions.html#exceptions.StopIterationNein. Das ähnlichste Konzept ist höchstwahrscheinlich eine StopIteration-Ausnahme.
Ich glaube, Python hat nur next () und laut Dokument gibt es eine Ausnahme, wenn es keine weiteren Elemente gibt.
Der Anwendungsfall, der mich dazu veranlasst hat, danach zu suchen, ist der folgende
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
wo hasnext () verfügbar ist, könnte man tun
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)
was für mich sauberer ist. Natürlich können Sie Probleme umgehen, indem Sie Dienstprogrammklassen definieren. In diesem Fall gibt es jedoch eine Vielzahl von zwanzig verschiedenen, fast gleichwertigen Problemumgehungen mit jeweils eigenen Macken. Wenn Sie Code wiederverwenden möchten, der unterschiedliche Problemumgehungen verwendet, müssen Sie dies auch tun Sie können mehrere nahezu gleichwertige Elemente in Ihrer einzelnen Anwendung verwenden oder Code durchlesen und neu schreiben, um denselben Ansatz zu verwenden. Die Maxime "Mach es einmal und mach es gut" schlägt schlecht fehl.
Darüber hinaus muss der Iterator selbst eine interne 'hasnext'-Prüfung durchführen, um festzustellen, ob eine Ausnahme ausgelöst werden muss. Diese interne Prüfung wird dann ausgeblendet, sodass sie getestet werden muss, indem versucht wird, ein Element abzurufen, die Ausnahme abzufangen und den Handler auszuführen, wenn er ausgelöst wird. Dies ist unnötig, IMO zu verstecken.
Vorgeschlagener Weg ist StopIteration . Bitte beachten Sie das Fibonacci-Beispiel von tutorialspoint
#!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()
Die Art und Weise, wie ich mein Problem gelöst habe, besteht darin, die Anzahl der bisher iterierten Objekte beizubehalten. Ich wollte eine Menge mit Aufrufen einer Instanzmethode durchlaufen. Da ich die Länge des Sets und die Anzahl der bisher gezählten Gegenstände kannte, hatte ich effektiv einehasNext
Methode.
Eine einfache Version meines Codes:
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
Natürlich ist das Beispiel ein Spielzeug, aber Sie bekommen die Idee. Dies funktioniert nicht in Fällen, in denen es nicht möglich ist, die Länge des Iterables zu ermitteln, wie z. B. bei einem Generator usw.