Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

228
Vistas
¿Por qué `map` oculta un `StopIteration`?

Encontré un caso en el que el uso de map() no es equivalente a la comprensión de una lista. Ocurre cuando se usa a next como primer argumento.

Por ejemplo:

 l1 = [1, 2] l2 = ['hello', 'world'] iterators = [iter(l1), iter(l2)] # list comprehension values1 = [next(it) for it in iterators] # values1 = [1, "hello"] values2 = [next(it) for it in iterators] # values2 = [2, "world"] values3 = [next(it) for it in iterators] # raise StopIteration
 l1 = [1, 2] l2 = ['hello', 'world'] iterators = [iter(l1), iter(l2)] # map values1 = list(map(next, iterators)) # values1 = [1, "hello"] values2 = list(map(next, iterators)) # values2 = [2, "world"] values3 = list(map(next, iterators)) # values3 = [] # doesn't raise StopIteration

Cualquier otra excepción ocurre como debería. Ejemplo:

 def divide_by_zero(value: int): return value // 0 l = [1, 2, 3] values = list(map(divide_by_zero, l)) # raises ZeroDivisionError as expected values = [divide_by_zero(value) for value in l] # raises ZeroDivisionError as expected, too

Parece muy extraño. Funciona igual con Python 3.9 y Python 3.11.

Parece que map() funciona así:

 def map(func, iterator): try: while True: item = next(iterator) yield func(item) except StopIteration: pass

pero esperaba que funcionara así:

 def map(func, iterator): while True: try: item = next(iterator) except StopIteration: break yield func(item)

¿Es un error?

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Intente llamar next en el map :

 >>> >>> m = map(next, iterators) >>> next(m) 1 >>> next(m) 'hello' >>> next(m) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration

Es la list que ve StopIteration y la usa para detener la construcción de la lista a partir de lo que produce el map .

La comprensión de la lista, por otro lado, está construyendo la lista iterando sobre iterators , no un iterador particular en esa lista. Es decir, next(it) se usa para producir un valor para la lista, no para determinar si hemos llegado al final de los iterators .

over 4 years ago · Santiago Trujillo Denunciar

0

Parece que ha encontrado uno de los raros casos en los que permitir que StopIteration aparezca como una excepción provoca un comportamiento incorrecto. No es un error, es solo una consecuencia desafortunada de la decisión de diseño de Python de usar una excepción para señalar el final de un iterador; es una trampa, como los argumentos predeterminados mutables , excepto que aparece con mucha menos frecuencia.

Como señala la respuesta de @chepner, el problema es que la list está capturando StopIteration y, por lo tanto, pensando que el map está agotado, cuando lo que realmente sucedió es que la función de next de llamada generó una excepción que desea tratar como una excepción real, es decir, una condición de falla .

Para evitar esto, en términos generales, no debe permitir que se llame a next en un contexto en el que StopIteration pueda surgir y quedar atrapado en el lugar equivocado. Si desea pasar next como una devolución de llamada, le sugiero que escriba un contenedor a next que convierta StopIteration en una excepción que no se malinterpretará como el final de algún otro iterador:

 def safe_next(it): try: return next(it) except StopIteration: raise ValueError('Unexpected end of iterator')

Ejemplo de uso:

 >>> l1 = [1, 2] >>> l2 = ['hello', 'world'] >>> iterators = [iter(l1), iter(l2)] >>> list(map(safe_next, iterators)) [1, 'hello'] >>> list(map(safe_next, iterators)) [2, 'world'] >>> list(map(safe_next, iterators)) Traceback (most recent call last): File "<stdin>", line 3, in safe_next StopIteration During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 5, in safe_next ValueError: Unexpected end of iterator

Dicho esto, en este caso de uso probablemente deberías usar zip :

 >>> pairs = zip(l1, l2) >>> next(pairs) (1, 'hello') >>> next(pairs) (2, 'world') >>> next(pairs) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda