standard - python pep indentation




No Lambda multilínea en Python: ¿Por qué no? (6)

(Para cualquier persona aún interesada en el tema.)

Considere esto (incluye incluso el uso de los valores de retorno de las declaraciones en otras declaraciones dentro del lambda "multilínea", aunque es feo hasta el punto de vomitar ;-)

>>> def foo(arg):
...     result = arg * 2;
...     print "foo(" + str(arg) + ") called: " + str(result);
...     return result;
...
>>> f = lambda a, b, state=[]: [
...     state.append(foo(a)),
...     state.append(foo(b)),
...     state.append(foo(state[0] + state[1])),
...     state[-1]
... ][-1];
>>> f(1, 2);
foo(1) called: 2
foo(2) called: 4
foo(6) called: 12
12

He oído decir que las lambdas multilínea no se pueden agregar en Python porque chocan sintácticamente con las otras construcciones de sintaxis en Python. Hoy pensé en esto en el autobús y me di cuenta de que no podía pensar en una sola construcción Python con la que las lambda multilínea chocaran. Dado que conozco bastante bien el idioma, esto me sorprendió.

Ahora, estoy seguro de que Guido tenía una razón para no incluir las lambdas multilínea en el lenguaje, pero por curiosidad: ¿cuál es una situación en la que incluir una lambda multilínea sería ambiguo? ¿Es verdad lo que he oído o hay alguna otra razón por la que Python no permite lambda multilínea?


Déjame tratar de abordar el problema de análisis de @balpha. Usaría paréntesis alrededor de la lamda multilínea. Si no hay paréntesis, la definición de lambda es codiciosa. Así que la lambda en

map(lambda x:
      y = x+1
      z = x-1
      y*z,
    [1,2,3]))

devuelve una función que devuelve (y*z, [1,2,3])

Pero

map((lambda x:
      y = x+1
      z = x-1
      y*z)
    ,[1,2,3]))

medio

map(func, [1,2,3])

donde func es la lambda multilínea que devuelve y * z. ¿Eso funciona?


Esto generalmente es muy feo (pero a veces las alternativas son aún más feas), por lo que una solución es hacer una expresión de llaves:

lambda: (
    doFoo('abc'),
    doBar(123),
    doBaz())

Sin embargo, no aceptará ninguna asignación, por lo que tendrá que preparar los datos de antemano. El lugar en el que encontré esto útil es el contenedor PySide, donde a veces tiene devoluciones de llamadas cortas. Escribir funciones miembro adicionales sería aún más feo. Normalmente no necesitarás esto.

Ejemplo:

pushButtonShowDialog.clicked.connect(
    lambda: (
    field1.clear(),
    spinBox1.setValue(0),
    diag.show())

Guido van Rossum (el inventor de Python) responde esta pregunta exacta en una antigua publicación del blog .
Básicamente, admite que es teóricamente posible, pero que cualquier solución propuesta sería no pitónica:

"Pero para mí, la complejidad de cualquier solución propuesta para este rompecabezas es inmensa: requiere que el analizador (o más precisamente, el lexer) sea capaz de alternar entre los modos sensible a la sangría e insensible a la sangría, manteniendo una pila de modos y nivel de sangría anteriores. Técnicamente eso se puede resolver (ya hay una pila de niveles de sangrado que pueden generalizarse). Pero nada de eso me quita la sensación de que todo es un artilugio elaborado por Rube Goldberg ".


Permítanme presentarles un truco glorioso pero aterrador:

lambda a, b: [(0, 9), (2, 3)][a<4][b>3]

Ahora puede utilizar este formulario LET como tal:

lambda x: [n**2 for n in x] #Assuming x is a list or tuple in this case

lo que da: [0, 3, 8]


Un par de enlaces relevantes:

Por un tiempo, estuve siguiendo el desarrollo de Reia, que inicialmente iba a tener la sintaxis basada en la sangría de Python con bloques de Ruby también, todo sobre Erlang. Pero, el diseñador terminó renunciando a la sensibilidad de sangría, y esta publicación que escribió sobre esa decisión incluye una discusión sobre los problemas que encontró con la sangría + los bloques de líneas múltiples, y una mayor apreciación que obtuvo por los problemas / decisiones de diseño de Guido:

http://www.unlimitednovelty.com/2009/03/indentation-sensitivity-post-mortem.html

Además, aquí hay una propuesta interesante para los bloques de estilo Ruby en Python que encontré donde Guido publica una respuesta sin disparar (aunque no estoy seguro de si ha habido algún disparo posterior):

http://tav.espians.com/ruby-style-blocks-in-python.html





lambda