Les itérateurs Python n'ont-ils pas de hasNext
méthode?
Les itérateurs Python n'ont-ils pas de hasNext
méthode?
Réponses:
Non, une telle méthode n'existe pas. La fin de l'itération est indiquée par une exception. Consultez la documentation .
unnext()
méthode pour remettre le premier élément après avoir vérifié qu'il existe en appelant next()
.
yield
ou non). Il n'est bien sûr pas difficile d'écrire un adaptateur qui stocke le résultat de next()
et fournit has_next()
et move_next()
.
hasNext()
méthode (pour produire, mettre en cache et renvoyer true en cas de succès, ou renvoyer false en cas d'échec). Ensuite , à la fois hasNext()
et next()
dépendrait d'un sous - jacent commun getNext()
méthode et élément mis en cache. Je ne vois vraiment pas pourquoi next()
ne devrait pas être dans la bibliothèque standard s'il est si facile d'implémenter un adaptateur qui le fournit.
next()
et hasNext()
méthode, pas seulement une bibliothèque Python hypothétique). Alors oui, next()
et cela hasNext()
devient délicat si le contenu du flux analysé dépend du moment où les éléments sont lus.
Il existe une alternative à l' StopIteration
utilisation de next(iterator, default_value)
.
Par exemple:
>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None
Ainsi, vous pouvez détecter pour None
ou toute autre valeur pré-spécifiée pour la fin de l'itérateur si vous ne voulez pas la manière d'exception.
sentinel = object()
et next(iterator, sentinel)
et tester avec is
.
unittest.mock.sentinel
objet intégré qui vous permet d'écrire un explicite next(a, sentinel.END_OF_ITERATION)
, puisif next(...) == sentinel.END_OF_ITERATION
Si vous avez vraiment besoin d' une has-next
fonctionnalité (parce que vous ne faites que transcrire fidèlement un algorithme à partir d'une implémentation de référence en Java, par exemple, ou parce que vous écrivez un prototype qui devra être facilement transcrit en Java une fois terminé), il est facile de obtenez-le avec une petite classe wrapper. Par exemple:
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
maintenant quelque chose comme
x = hn_wrapper('ciao')
while x.hasnext(): print next(x)
émet
c
i
a
o
comme demandé.
Notez que l'utilisation de next(sel.it)
comme élément intégré nécessite Python 2.6 ou supérieur; si vous utilisez une ancienne version de Python, utilisez à la self.it.next()
place (et de la même manière next(x)
dans l'exemple d'utilisation). [[Vous pourriez raisonnablement penser que cette note est redondante, puisque Python 2.6 existe depuis plus d'un an maintenant - mais plus souvent qu'autrement lorsque j'utilise les fonctionnalités de Python 2.6 dans une réponse, certains commentateurs ou autres se sentent obligés de signaler qu'il s'agit de fonctionnalités 2.6, j'essaye donc de prévenir de tels commentaires pour une fois ;-)]]
has_next
méthode. La conception de Python rend impossible, par exemple, d'utiliser filter
pour vérifier si un tableau contient un élément correspondant à un prédicat donné. L'arrogance et la myopie de la communauté Python sont stupéfiantes.
TypeError: iter() returned non-iterator
map
et any
au lieu de filter
, mais vous pouvez utiliser SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL
ou oublier a SENTINEL
et simplement utiliser try: except
et attraper le StopIteration
.
En plus de toutes les mentions de StopIteration, la boucle Python "for" fait simplement ce que vous voulez:
>>> it = iter("hello")
>>> for i in it:
... print i
...
h
e
l
l
o
Essayez la méthode __length_hint __ () à partir de n'importe quel objet itérateur:
iter(...).__length_hint__() > 0
__init__
et __main__
? Imho, c'est un peu le bordel, peu importe que vous essayez de le justifier.
hasNext
se traduit quelque peu par l' StopIteration
exception, par exemple:
>>> 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
docs: http://docs.python.org/library/exceptions.html#exceptions.StopIterationNon. Le concept le plus similaire est probablement une exception StopIteration.
Je crois que python a juste next () et selon la doc, il lève une exception est qu'il n'y a plus d'éléments.
Le cas d'utilisation qui m'a conduit à rechercher ceci est le suivant
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
où hasnext () est disponible, on pourrait faire
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)
ce qui pour moi est plus propre. De toute évidence, vous pouvez contourner les problèmes en définissant des classes d'utilitaires, mais ce qui se passe alors, c'est que vous avez une prolifération de vingt solutions de contournement presque équivalentes différentes, chacune avec leurs bizarreries, et si vous souhaitez réutiliser du code qui utilise différentes solutions de contournement, vous devez soit avoir plusieurs quasi-équivalents dans votre application unique, ou parcourir et réécrire du code pour utiliser la même approche. La maxime «faites-le une fois et faites-le bien» échoue gravement.
De plus, l'itérateur lui-même a besoin d'une vérification interne 'hasnext' pour s'exécuter pour voir s'il a besoin de lever une exception. Cette vérification interne est ensuite masquée afin qu'elle doive être testée en essayant d'obtenir un élément, en interceptant l'exception et en exécutant le gestionnaire s'il est levé. Il s'agit de cacher l'OMI inutile.
La méthode suggérée est StopIteration . S'il vous plaît voir l'exemple Fibonacci de 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()
La façon dont j'ai résolu mon problème est de garder le décompte du nombre d'objets itérés jusqu'à présent. Je voulais parcourir un ensemble en utilisant des appels à une méthode d'instance. Puisque je connaissais la longueur de l'ensemble et le nombre d'articles comptés jusqu'à présent, j'avais effectivement unhasNext
méthode.
Une version simple de mon code:
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
Bien sûr, l'exemple est un jouet, mais vous voyez l'idée. Cela ne fonctionnera pas dans les cas où il n'y a aucun moyen d'obtenir la longueur de l'itérable, comme un générateur, etc.