Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

255
Views
¿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 answers
Answer question

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!