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

254
Vistas
¿La comprensión del generador es diferente de la comprensión de la lista?

Obtengo un resultado diferente cuando uso una comprensión de lista versus una comprensión de generador. ¿Es este comportamiento esperado o un error?

Considere la siguiente configuración:

 all_configs = [ {'a': 1, 'b':3}, {'a': 2, 'b':2} ] unique_keys = ['a','b']

Si luego ejecuto el siguiente código, obtengo:

 print(list(zip(*( [c[k] for k in unique_keys] for c in all_configs)))) >>> [(1, 2), (3, 2)] # note the ( vs [ print(list(zip(*( (c[k] for k in unique_keys) for c in all_configs)))) >>> [(2, 2), (2, 2)]

Esto está en python 3.6.0:

 Python 3.6.0 (default, Dec 24 2016, 08:01:42) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

En una lista de comprensión, las expresiones se evalúan con entusiasmo. En una expresión de generador, solo se buscan según sea necesario.

Por lo tanto, a medida que la expresión del generador itera sobre for c in all_configs , se refiere a c[k] pero solo busca c después de que finaliza el ciclo, por lo que solo usa el valor más reciente para ambas tuplas. Por el contrario, la comprensión de listas se evalúa inmediatamente, por lo que crea una tupla con el primer valor de c y otra tupla con el segundo valor de c .

Considere este pequeño ejemplo:

 >>> r = range(3) >>> i = 0 >>> a = [i for _ in r] >>> b = (i for _ in r) >>> i = 3 >>> print(*a) 0 0 0 >>> print(*b) 3 3 3

Al crear a , el intérprete creó esa lista inmediatamente, buscando el valor de i tan pronto como se evaluó. Al crear b , el intérprete simplemente configuró ese generador y en realidad no iteró sobre él y buscó el valor de i . Las llamadas de print le dijeron al intérprete que evaluara esos objetos. a ya existía como una lista completa en la memoria con el valor anterior de i , pero b se evaluó en ese momento, y cuando buscó el valor de i , encontró el nuevo valor.

over 4 years ago · Santiago Trujillo Denunciar

0

Para ver qué está pasando, reemplace c[k] con una función con un efecto secundario:

 def f(c,k): print(c,k) return c[k] print("listcomp") print(list(zip(*( [f(c,k) for k in unique_keys] for c in all_configs)))) print("gencomp") print(list(zip(*( (f(c,k) for k in unique_keys) for c in all_configs))))

producción:

 listcomp {'a': 1, 'b': 3} a {'a': 1, 'b': 3} b {'a': 2, 'b': 2} a {'a': 2, 'b': 2} b [(1, 2), (3, 2)] gencomp {'a': 2, 'b': 2} a {'a': 2, 'b': 2} a {'a': 2, 'b': 2} b {'a': 2, 'b': 2} b [(2, 2), (2, 2)]

c en las expresiones del generador se evalúa después de que se haya completado el ciclo externo:

c lleva el último valor que tomó en el bucle exterior.

En el caso de comprensión de listas, c se evalúa de inmediato.

(tenga en cuenta que aabb vs abab también debido a la ejecución al comprimir vs ejecución a la vez)

tenga en cuenta que puede mantener la forma de "generador" de hacerlo (sin crear la lista temporal) pasando c al map para que se almacene el valor actual:

 print(list(zip(*( map(c.get,unique_keys) for c in all_configs))))

en Python 3, el map no crea una list , pero el resultado sigue siendo correcto: [(1, 2), (3, 2)]

over 4 years ago · Santiago Trujillo Denunciar

0

Esto sucede porque la llamada zip(*) resultó en la evaluación del generador externo y este externo devolvió dos generadores más.

 (c[k], print(c)) for k in unique_keys)

La evaluación del generador externo movió c al segundo dict: {'a': 2, 'b':2} .

Ahora, cuando estamos evaluando estos generadores individualmente, buscan c en alguna parte, y como su valor ahora es {'a': 2, 'b':2} obtienes el resultado como [(2, 2), (2, 2)] .

Manifestación:

 >>> def my_zip(*args): ... print(args) ... for arg in args: ... print (list(arg)) ... ... my_zip(*((c[k] for k in unique_keys) for c in all_configs)) ...

Producción:

 # We have two generators now, means it has looped through `all_configs`. (<generator object <genexpr>.<genexpr> at 0x104415c50>, <generator object <genexpr>.<genexpr> at 0x10416b1a8>) [2, 2] [2, 2]

La lista de comprensión, por otro lado, se evalúa de inmediato y puede obtener el valor del valor actual de c no su último valor.


¿Cómo forzarlo a usar el valor correcto de c ?

Utilice una función interna y una función de generador. La función interna puede ayudarnos a recordar el valor de c usando el argumento predeterminado.

 >>> def solve(): ... for c in all_configs: ... def func(c=c): ... return (c[k] for k in unique_keys) ... yield func() ... >>> >>> list(zip(*solve())) [(1, 2), (3, 2)]
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