Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

229
Visualizações
¿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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda