¿Los iteradores de Python no tienen un hasNext
método?
¿Los iteradores de Python no tienen un hasNext
método?
Respuestas:
No, no existe tal método. El final de la iteración se indica mediante una excepción. Ver la documentación .
unnext()
método para volver a colocar el primer elemento después de haber comprobado que existe llamando next()
.
yield
o no). Por supuesto, no es difícil escribir un adaptador que almacene el resultado next()
y proporcione has_next()
y move_next()
.
hasNext()
método (para producir, almacenar en caché y devolver verdadero en caso de éxito o falso en caso de error). Entonces ambos hasNext()
y next()
dependerían de un getNext()
método subyacente común y un elemento en caché. Realmente no veo por next()
qué no debería estar en la biblioteca estándar si es tan fácil implementar un adaptador que lo proporciona.
next()
y hasNext()
método, no solo una hipotética biblioteca de Python). Entonces sí, next()
y se hasNext()
vuelve complicado si el contenido de la secuencia que se escanea depende de cuándo se leen los elementos.
Hay una alternativa al StopIteration
uso next(iterator, default_value)
.
Por ejemplo:
>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None
Por lo tanto, puede detectar None
u otro valor preespecificado para el final del iterador si no desea la forma de excepción.
sentinel = object()
y next(iterator, sentinel)
y probar con is
.
unittest.mock.sentinel
objeto incorporado que le permita escribir un mensaje explícito next(a, sentinel.END_OF_ITERATION)
y luegoif next(...) == sentinel.END_OF_ITERATION
Si realmente necesita una has-next
funcionalidad (porque solo está transcribiendo fielmente un algoritmo de una implementación de referencia en Java, por ejemplo, o porque está escribiendo un prototipo que deberá transcribirse fácilmente a Java cuando esté terminado), es fácil obténgalo con una pequeña clase de envoltura. Por ejemplo:
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
ahora algo como
x = hn_wrapper('ciao')
while x.hasnext(): print next(x)
emite
c
i
a
o
según sea necesario.
Tenga en cuenta que el uso de next(sel.it)
como incorporado requiere Python 2.6 o superior; si está utilizando una versión anterior de Python, use self.it.next()
en su lugar (y de manera similar para next(x)
el uso de ejemplo). [[Puede pensar razonablemente que esta nota es redundante, ya que Python 2.6 ha existido por más de un año, pero la mayoría de las veces cuando uso las características de Python 2.6 en una respuesta, algunos comentaristas u otros se sienten obligados a señalar que son características 2.6, por lo que estoy tratando de evitar tales comentarios por una vez ;-)]]
has_next
método. El diseño de Python hace imposible, por ejemplo, usar filter
para verificar si una matriz contiene un elemento que coincide con un predicado dado. La arrogancia y la miopía de la comunidad de Python es asombrosa.
TypeError: iter() returned non-iterator
map
y en any
lugar de filter
, pero podría usar SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL
u olvidar ay SENTINEL
simplemente usar try: except
y capturar el StopIteration
.
Además de todas las menciones de StopIteration, el bucle "for" de Python simplemente hace lo que desea:
>>> it = iter("hello")
>>> for i in it:
... print i
...
h
e
l
l
o
Pruebe el método __length_hint __ () desde cualquier objeto iterador:
iter(...).__length_hint__() > 0
__init__
y __main__
? En mi humilde opinión, es un desastre, no importa si tratas de justificarlo.
hasNext
algo se traduce a la StopIteration
excepción, por ejemplo:
>>> 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.StopIterationNo. El concepto más similar es probablemente una excepción StopIteration.
Creo que Python solo tiene next () y, según el documento, arroja una excepción si no hay más elementos.
El caso de uso que me llevó a buscar esto es el siguiente
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
donde hasnext () está disponible, uno podría hacer
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)
que para mí es más limpio Obviamente, puede solucionar los problemas definiendo las clases de utilidad, pero lo que sucede es que tiene una proliferación de veinte soluciones alternativas casi equivalentes diferentes, cada una con sus peculiaridades, y si desea reutilizar el código que utiliza soluciones alternativas diferentes, debe tenga múltiples casi equivalentes en su única aplicación, o busque y reescriba el código para usar el mismo enfoque. La máxima de "hazlo una vez y hazlo bien" falla gravemente.
Además, el iterador en sí mismo necesita tener una verificación interna 'hasnext' para ejecutarse para ver si necesita generar una excepción. Esta comprobación interna se oculta, por lo que debe probarse intentando obtener un elemento, capturando la excepción y ejecutando el controlador si se produce. Esto es innecesario para ocultar IMO.
La forma sugerida es StopIteration . Por favor vea el ejemplo de Fibonacci desde 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 forma en que resolví mi problema es mantener el recuento de la cantidad de objetos iterados, hasta ahora. Quería iterar sobre un conjunto utilizando llamadas a un método de instancia. Como sabía la longitud del conjunto y la cantidad de elementos contados hasta ahora, efectivamente tuve un hasNext
método.
Una versión simple de mi código:
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
Por supuesto, el ejemplo es de juguete, pero se entiende la idea. Esto no funcionará en casos donde no hay forma de obtener la longitud del iterable, como un generador, etc.