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

100
Vistas
Asegúrese de que un argumento se pueda iterar dos veces

Supongamos que tengo la siguiente función:

 def print_twice(x): for i in x: print(i) for i in x: print(i)

Cuando corro:

 print_twice([1,2,3])

o:

 print_twice((1,2,3))

Obtengo el resultado esperado: los números 1,2,3 se imprimen dos veces.

Pero cuando corro:

 print_twice(zip([1,2,3],[4,5,6]))

los pares (1,4),(2,5),(3,6) se imprimen una sola vez. Probablemente, esto se deba a que el zip devuelve un generador que finaliza después de una pasada.

¿Cómo puedo modificar la función print_twice para que maneje correctamente todas las entradas?

Podría insertar una línea al principio de la función: x = list(x) . Pero esto podría ser ineficiente en caso de que x ya sea una lista, una tupla, un rango o cualquier otro iterador que pueda iterarse más de una vez. ¿Hay una solución más eficiente?

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

0

Podría insertar una línea al principio de la función: x = list(x) . Pero esto podría ser ineficiente en caso de que x ya sea una lista, una tupla, un rango o cualquier otro iterador que pueda iterarse más de una vez. ¿Hay una solución más eficiente?

Copiar iterables de un solo uso en una list es perfectamente adecuado y razonablemente eficiente incluso para iterables de usos múltiples.

El tipo de list (y hasta cierto punto tuple ) es una de las estructuras de datos más optimizadas en Python. Las operaciones comunes, como copiar una list o una tuple a una list , se optimizan internamente; 1 incluso para iterables que no tienen un caso especial, copiarlos en una list es significativamente más rápido que cualquier trabajo realista realizado por dos (o más) bucles.

 def print_twice(x): x = list(x) for i in x: print(i) for i in x: print(i)

La copia indiscriminada también puede ser ventajosa en el contexto de la concurrencia, cuando el iterable se puede modificar mientras se ejecuta la función. Los casos comunes son subprocesos y colecciones de weakref .


En caso de que uno quiera evitar copias innecesarias, verificar si el iterable es una Collection es un resguardo razonable.

 from collections.abc import Collection x = list(x) if not isinstance(x, Collection) else x

Alternativamente, uno puede verificar si el iterable es de hecho un iterado o , ya que esto implica estado y, por lo tanto, un solo uso.

 from collections.abc import Iterator x = list(x) if isinstance(x, Iterator) else x x = list(x) if iter(x) is x else x

En particular, los componentes zip , filter , map , ... y generadores son todos iteradores.


1 Copiar una list de 128 elementos es aproximadamente tan rápido como comprobar si se trata de una Collection .

over 4 years ago · Santiago Trujillo Denunciar

0

Una prueba simple para ver si x se consumirá cuando lo repita es iter(x) is x . Esto es confiable, ya que se especifica como parte del protocolo iterador ( docs ):

Se requiere que los iteradores tengan un __iter__() que devuelva el propio objeto del iterador

Por el contrario, si iter(x) devuelve x , entonces x debe ser un iterador, ya que fue devuelto por la función iter .

Algunos cheques:

 def is_iterator(x): return iter(x) is x for obj in [ # not iterators [1, 2, 3], (1, 2, 3), {1: 2, 3: 4}, range(3), # iterators (x for x in range(3)), iter([1, 2, 3]), zip([1, 2], [3, 4]), filter(lambda x: x % 2 == 0, [1, 2, 3]), map(lambda x: 2 * x, [1, 2, 3]), ]: name = type(obj).__name__ if is_iterator(obj): print(name, 'is an iterator') else: print(name, 'is not an iterator')

Resultados:

 list is not an iterator tuple is not an iterator dict is not an iterator range is not an iterator generator is an iterator list_iterator is an iterator zip is an iterator filter is an iterator map is an iterator

Entonces, para asegurarse de que x se pueda iterar varias veces, sin hacer una copia innecesaria si ya se puede, puede escribir algo como:

 if iter(x) is x: x = list(x)
over 4 years ago · Santiago Trujillo Denunciar

0

zip devolverá un iterador. Una vez desempaquetado, no se puede volver a desempaquetar, se agota.

Tal vez si desea asegurarse de que solo los objetos zip se conviertan a la list como dijo que funcionaría pero no sería eficiente, puede verificarlo escriba:

 if isinstance(x, zip): x = list(x)
over 4 years ago · Santiago Trujillo Denunciar

0

Modifique su función print_twice

 def print_twice(x): val = x for i in range(2): for i in val: print(i)
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