¿Por qué la salida de los dos siguientes en la lista de comprensión diferente, aunque f y la lambda función son los mismos?

f = lambda x: x*x
[f(x) for x in range(10)]

y

[lambda x: x*x for x in range(10)]

Mente, tanto type(f) y type(lambda x: x*x) devolver el mismo tipo.

  • [lambda x: x*x for x in range(10)] es más rápido que el primero, ya que no llame a un fuera de la función de bucle, f repetidamente.
  • en lugar de crear un nuevo y flamante función de cada uno y cada vez a través del bucle. …y la sobrecarga de la creación de esta nueva función, a continuación, llamar es un poco más lento (en mi sistema, de todos modos).
  • Incluso con sobrecarga, es todavía más rápido. Pero, por supuesto [x*x for x in range(10)] es mejor.
  • He entrado aquí para obtener google foobar acceso 🙂
InformationsquelleAutor user763191 | 2011-05-20

6 Comentarios

  1. 224

    El primero crear una única función lambda y la llama diez veces.

    El segundo no llamar a la función. Crea 10 diferentes las funciones lambda. Coloca todos los en una lista. Para hacerla equivalente a la primera necesidad:

    [(lambda x: x*x)(x) for x in range(10)]

    O mejor aún:

    [x*x for x in range(10)]
    • O map(lambda x: x*x, range(10)), que era probablemente lo que el OP se entiende en el primer lugar.
    • sí, lambda x : x*x .. (x) parece tenet.
    • [lambda x: x*x for x in range(10)] es básicamente un functur en haskell
  2. 79

    Esta pregunta toca un punto muy apestoso parte de la «famosa» y «obvio» que la sintaxis de Python – lo que tiene prioridad, el lambda, o el porque de la lista de comprensión.

    No creo que el propósito de la OP fue generar una lista de plazas de 0 a 9. Si ese fuera el caso, podríamos dar más soluciones:

    squares = []
    for x in range(10): squares.append(x*x)
    • este es el buen ol’ forma de imperativo sintaxis.

    Pero no es el punto. El punto es W(hy)TF es esta ambigua expresión tan contra-intuitivo? Y tengo una idiota caso para usted en el final, por lo que no descartan mi respuesta demasiado temprano (yo lo tenía en una entrevista de trabajo).

    Así, el OP de la comprensión devuelve una lista de expresiones lambda:

    [(lambda x: x*x) for x in range(10)]

    Esto es, por supuesto, a sólo 10 diferentes copias de la cuadratura de la función, véase:

    >>> [lambda x: x*x for _ in range(3)]
    [<function <lambda> at 0x00000000023AD438>, <function <lambda> at 0x00000000023AD4A8>, <function <lambda> at 0x00000000023AD3C8>]

    Nota las direcciones de memoria de las funciones lambda – todos ellos son diferentes!

    Usted podría, por supuesto, tienen una más «óptimo» (jaja) versión de esta expresión:

    >>> [lambda x: x*x] * 3
    [<function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>]

    Ver? 3 tiempo el mismo lambda.

    Tenga en cuenta, que he usado _ como el for variable. No tiene nada que ver con la x en el lambda (es eclipsado léxicamente!). Get it?

    Estoy dejando fuera de la discusión, ¿por qué la sintaxis de precedencia no es así, que todo significaba:

    [lambda x: (x*x for x in range(10))]

    que puede ser: [[0, 1, 4, ..., 81]], o [(0, 1, 4, ..., 81)], o que me parece más lógico, este sería un list de 1 elemento – una generator devolución de los valores. No es el caso, el lenguaje no funciona de esta manera.

    PERO Qué, Si…

    Lo que si NO eclipsar a la for variable, Y utilizar en su lambdas???

    Bien, entonces la mierda ocurre. Mira esto:

    [lambda x: x * i for i in range(4)]

    esto significa, por supuesto:

    [(lambda x: x * i) for i in range(4)]

    PERO NO significa:

    [(lambda x: x * 0), (lambda x: x * 1), ... (lambda x: x * 3)]

    Este está loco!

    La lambdas en la lista de comprensión son un cierre sobre el ámbito de aplicación de esta comprensión. Un léxica de cierre, de modo que se refieren a la i a través de la referencia, y no su valor cuando se evaluaron!

    Así, esta expresión:

    [(lambda x: x * i) for i in range(4)]

    ES aproximadamente EQUIVALENTE a:

    [(lambda x: x * 3), (lambda x: x * 3), ... (lambda x: x * 3)]

    Estoy seguro de que podríamos ver más aquí usando python decompiler (con lo que quiero decir por ejemplo, la dis módulo), pero para Python-VM-agnóstico discusión esto es suficiente.
    Tanto para el trabajo pregunta de la entrevista.

    Ahora, cómo hacer una list de multiplicador de lambdas, que realmente multiplicar por números enteros consecutivos? Así, de manera similar a la aceptación de la respuesta, necesitamos romper la relación directa con el i envolviendo en otro lambda, que está recibiendo la llamada dentro de la lista de la comprensión de la expresión:

    Antes:

    >>> a = [(lambda x: x * i) for i in (1, 2)]
    >>> a[1](1)
    2
    >>> a[0](1)
    2

    Después:

    >>> a = [(lambda y: (lambda x: y * x))(i) for i in (1, 2)]
    >>> a[1](1)
    2
    >>> a[0](1)
    1

    (Yo tuve el exterior lambda variable = i, pero he decidido que esta es la más clara de la solución – me introdujo y para que todos podamos ver que la bruja es que).

    Editar 2019-08-30:

    Tras una sugerencia de @josoler, que también está presente en una respuesta por @sheridp – el valor de la lista de la comprensión de la «variable de bucle» puede ser «integrados» dentro de un objeto – la clave es que se puede acceder en el momento adecuado. La sección «Después de» de arriba, envolviéndolo en otro lambda y llamar de inmediato con el valor actual de i. De otra manera (un poco más fácil de leer – no produce » WAT » efecto) es almacenar el valor de i dentro de un partial objeto, y tiene el «interior» (original) lambda tomar como un argumento (que se pasa suministrados por el partial objeto en el momento de la llamada), es decir:

    Después de las 2:

    >>> from functools import partial
    >>> a = [partial(lambda y, x: y * x, i) for i in (1, 2)]
    >>> a[0](2), a[1](2)
    (2, 4)

    Grandes, pero todavía hay un pequeño giro para usted! Digamos que quieres para que sea más fácil para el lector de códigos, y pasar el factor por el nombre (como una palabra clave argumento para partial). Vamos a hacer algo de cambio de nombre de:

    Después de 2.5:

    >>> a = [partial(lambda coef, x: coef * x, coef=i) for i in (1, 2)]
    >>> a[0](1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: <lambda>() got multiple values for argument 'coef'

    WAT?

    >>> a[0]()
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: <lambda>() missing 1 required positional argument: 'x'

    Espera… estamos cambiando el número de argumentos por 1, y que van desde «demasiados» a «muy pocos»?

    Bueno, no es un verdadero WAT, cuando pasamos coef a partial de esta manera, se convierte en una palabra clave argumento, por lo que debe venir después de la posición x argumento, así:

    Después de las 3:

    >>> a = [partial(lambda x, coef: coef * x, coef=i) for i in (1, 2)]
    >>> a[0](2), a[1](2)
    (2, 4)

    Yo prefiero la última versión sobre la lambda anidada, pero a cada uno lo suyo…

    • que es un cruel e inusual entrevista de trabajo en cuestión.
    • Mi cabeza quemada de leer tu respuesta!
    • Si mi colega no pregunte, yo probablemente nunca la búsqueda de esta respuesta
    • Wow. Acabo de recibir mordido gravemente por este absurdo comportamiento. Gracias por tu post!
    • Excelente respuesta. Sólo me encontré con este problema. Por un lado es un Python limitación, pero por otro lado también podría ser un código de olor indicador. Estoy usando esta solución para un juguete proyecto, pero podría ser una señal de reestructuración en un entorno de producción.
    • Esto debería convertirse en el aceptado respuesta.
    • Por el bien de la claridad y la integridad podría escribir la última lista de comprensión como: [partial(lambda i, x: i * x, i) for i in (1, 2)]
    • Gracias @josoler, he añadido una sección sobre el uso de partial a mi respuesta.
    • Sólo para la integridad causa: La función de los objetos generados por la lambda anidada solución se encuentra en igual de loco direcciones, por ejemplo,<function run.<locals>.<listcomp>.<lambda>.<locals>.<lambda> at 0x1a1db776a8>.

  3. 18

    La gran diferencia es que en el primer ejemplo realmente llama la lambda f(x), mientras que el segundo ejemplo no.

    Su primer ejemplo es equivalente a [(lambda x: x*x)(x) for x in range(10)] mientras que el segundo ejemplo es equivalente a [f for x in range(10)].

  4. 9

    La primera

    f = lambda x: x*x
    [f(x) for x in range(10)]

    ejecuta f() para cada valor en el rango por lo que no f(x) para cada valor

    el segundo

    [lambda x: x*x for x in range(10)]

    se ejecuta la expresión lambda para cada valor de la lista, por lo que genera todas esas funciones.

  5. 5

    Personas dieron buenas respuestas, pero se olvidó de mencionar la parte más importante en mi opinión:
    En el segundo ejemplo de la X de la lista de comprensión NO es el mismo que el X de la lambda función, son totalmente ajenos.
    Así que el segundo ejemplo es de hecho la misma:

    [Lambda X: X*X for I in range(10)]

    El interior de iteraciones en range(10) sólo son responsables de la creación de 10 similares las funciones lambda en una lista (10 funciones separadas pero totalmente similares – devolver el poder 2 de cada entrada).

    Por otro lado, el primer ejemplo de obras totalmente diferentes, debido a que el X de las iteraciones interactúan con los resultados, para cada iteración el valor es X*X por lo que el resultado sería [0,1,4,9,16,25, 36, 49, 64 ,81]

    • Este es un punto importante. Yo upvoted usted y elaborados en mi respuesta.
  6. 4

    Las otras respuestas son correctas, pero si usted está tratando de hacer una lista de funciones, cada una con un parámetro, que puede ser ejecutado más tarde, el siguiente código hará que:

    import functools
    a = [functools.partial(lambda x: x*x, x) for x in range(10)]
    
    b = []
    for i in a:
        b.append(i())
    
    In [26]: b
    Out[26]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

    Mientras que el ejemplo es inventado, me pareció útil cuando yo quería una lista de las funciones que cada uno de imprimir algo diferente, es decir,

    import functools
    a = [functools.partial(lambda x: print(x), x) for x in range(10)]
    
    for i in a:
        i()

Dejar respuesta

Please enter your comment!
Please enter your name here