hasnext() para iteradores de Python?

5 minutos de lectura

Avatar de usuario de Juanjo Conti
Juanjo Conti

¿Los iteradores de Python tienen un hasnext ¿método?

  • Relacionado: ¿Cómo sé si un generador está vacío desde el principio?

    – usuario2314737

    5 de mayo de 2017 a las 10:58

  • No hay tal cosa a partir de ahora. Y creo que la forma correcta de hacer esto es agregar next y has_next en los propios iteradores, ya que estos métodos no deben definirse de forma independiente.

    –Shiv Krishna Jaiswal

    19 de febrero a las 3:47

Avatar de usuario de Derrick Zhang
Derrick Zhang

La alternativa a atrapar StopIteration es usar next(iterator, default_value).

Por ejemplo:

>>> a = iter('hi')
>>> print(next(a, None))
h
>>> print(next(a, None))
i
>>> print(next(a, None))
None

De esta manera puede verificar None para ver si ha llegado al final del iterador si no desea hacerlo de forma excepcional.

Si su iterable puede contener None valores tendrá que definir un valor centinela y verificarlo en su lugar:

>>> sentinel = object()
>>> a = iter([None, 1, 2])
>>> elem = next(a, sentinel)
>>> if elem is sentinel:
...     print('end')
... 
>>>

  • si usa Ninguno como “centinela”, es mejor que se asegure de que su iterador no tenga ningún Ninguno. también podrías hacer sentinel = object() y next(iterator, sentinel) y prueba con is.

    – sam boosalis

    03/10/2013 a las 18:00


  • siguiendo a @samboosalis, preferiría usar incorporado unittest.mock.sentinel objeto que le permite escribir un explícito next(a, sentinel.END_OF_ITERATION) y luego if next(...) == sentinel.END_OF_ITERATION

    – Clemente Walter

    1 dic 2018 a las 19:40

  • El problema es que, de esta manera, también CONSUMES el siguiente valor del iterador. hasNext en Java no consume el siguiente valor.

    – Alan Franzoni

    17 de julio de 2020 a las 12:18

No, no existe tal método. El final de la iteración se indica mediante una excepción. Ver el documentación.

  • “Es más fácil pedir perdón que permiso”.

    Roger Paté

    27 de diciembre de 2009 a las 18:57

  • “Es más fácil pedir perdón que permiso”: verificar si un iterador tiene un elemento siguiente no es pedir permiso. Hay situaciones en las que desea probar la existencia de un elemento siguiente sin consumirlo. Aceptaría la solución Try Catch si hubiera una unnext() método para volver a colocar el primer elemento después de haber verificado que existe llamando next().

    – Jorge

    24 de diciembre de 2012 a las 20:26

  • @Giorgio, no hay forma de saber si existe otro elemento sin ejecutar el código que lo genera (no sabe si el generador se ejecutará yield O no). Por supuesto, no es difícil escribir un adaptador que almacene el resultado de next() y proporciona has_next() y move_next().

    – Avakar

    24 de diciembre de 2012 a las 21:10

  • La misma idea podría usarse para implementar el hasNext() método (para producir, almacenar en caché y devolver verdadero en caso de éxito, o devolver falso en caso de error). Entonces ambos hasNext() y next() dependería de un subyacente común getNext() método y elemento en caché. Realmente no veo por qué next() no debería estar en la biblioteca estándar si es tan fácil implementar un adaptador que lo proporcione.

    – Jorge

    24 de diciembre de 2012 a las 21:21


  • @LarsH: ¿Quiere decir, por ejemplo, un iterador que lee de un archivo que se puede cambiar mientras se lee? Acepto que esto puede ser un problema (que afecta a cualquier biblioteca que proporcione next() y hasNext() método, no solo una biblioteca hipotética de Python). Entonces sí, next() y hasNext() se vuelve complicado si el contenido de la transmisión que se analiza depende de cuando se leen los elementos.

    – Jorge

    25 de enero de 2013 a las 6:42


Avatar de usuario de Alex Martelli
alex martelli

No, pero puede implementar su propia clase contenedora iterable que lo haga:

from collections.abc import Iterator

class hn_wrapper(Iterator):
    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

Entonces puedes usarlo así:

x = hn_wrapper('ciao')
while x.hasnext():
    print(next(x))

y emitirá

c
i
a
o

  • Sería un poco más pitónico implementar hasnext() como next()es decir, cambiar el nombre del método a hn_wrapper.__hasnext__() y luego definir una función de nivel superior que llame a ese método def hasnext(iterable): return iterable.__hasnext__().

    – Boris Verjovskiy

    30 abr a las 23:20


Avatar de usuario de Brian Clapper
Brian Clapper

Además de todas las menciones de StopIterationel pitón for loop hace lo que quieres:

>>> it = iter('hello')
>>> for i in it:
...     print(i)
...
h
e
l
l
o

avatar de usuario de juj
juj

Prueba el método __length_hint__() desde cualquier objeto iterador:

iter(...).__length_hint__() > 0

avatar de usuario de sykora
sykora

Puede tee el iterador usando, itertools.teey verifique StopIteration en el iterador teed.

hasNext algo se traduce en el 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

¿Ha sido útil esta solución?