Utilizo principalmente funciones lambda, pero a veces uso funciones anidadas que parecen proporcionar el mismo comportamiento.
Aquí hay algunos ejemplos triviales en los que funcionalmente hacen lo mismo si alguno de ellos se encontrara dentro de otra función:
Función lambda
>>> a = lambda x : 1 + x
>>> a(5)
6
Función anidada
>>> def b(x): return 1 + x
>>> b(5)
6
¿Hay ventajas de usar uno sobre el otro? (¿Rendimiento? ¿Legibilidad? ¿Limitaciones? ¿Consistencia? Etc.)
¿Incluso importa? Si no es así, entonces viola el principio Pythonic:
Debe haber una, y preferiblemente solo una, forma obvia de hacerlo .
lambda
, pero no estoy de acuerdo en que esto es "muy raro", es común para las funciones clavesorted
oitertools.groupby
etc., por ejemplosorted(['a1', 'b0'], key= lambda x: int(x[1]))
Prácticamente hablando, para mí hay dos diferencias:
La primera es sobre lo que hacen y lo que devuelven:
def es una palabra clave que no devuelve nada y crea un 'nombre' en el espacio de nombres local.
lambda es una palabra clave que devuelve un objeto de función y no crea un 'nombre' en el espacio de nombres local.
Por lo tanto, si necesita llamar a una función que toma un objeto de función, la única forma de hacerlo en una línea de código Python es con una lambda. No hay equivalente con def.
En algunos marcos, esto es bastante común; por ejemplo, utilizo Twisted mucho, por lo que hago algo como
es bastante común y más conciso con lambdas.
La segunda diferencia tiene que ver con lo que puede hacer la función real.
Por ejemplo,
funciona como se esperaba, mientras
es un SyntaxError.
Por supuesto, hay soluciones alternativas: sustitúyalas
print
consys.stdout.write
oimport
con__import__
. Pero normalmente es mejor optar por una función en ese caso.fuente
En esta entrevista, Guido van Rossum dice que desearía no haber dejado 'lambda' en Python:
En mi humilde opinión, las Iambdas pueden ser convenientes a veces, pero generalmente son convenientes a expensas de la legibilidad. ¿Puedes decirme qué hace esto?
Lo escribí y me tomó un minuto entenderlo. Esto es del Proyecto Euler; no diré qué problema porque odio los spoilers, pero se ejecuta en 0.124 segundos :)
fuente
lambda
no ser eliminado en 3.0 estuvo cerca, y que Guido no estaba luchando por mantenerlo.Para n = 1000, aquí hay algo de tiempo para llamar a una función frente a una lambda:
fuente
Actuación:
Crear una función con
lambda
es un poco más rápido que crearla condef
. La diferencia se debe a ladef
creación de una entrada de nombre en la tabla de locales. La función resultante tiene la misma velocidad de ejecución.Legibilidad:
Las funciones Lambda son algo menos legibles para la mayoría de los usuarios de Python, pero también mucho más concisas en algunas circunstancias. Considere la posibilidad de pasar de usar una rutina no funcional a una funcional:
Como puede ver, la
lambda
versión es más corta y "más fácil" en el sentido de que solo necesita agregarlambda v:
a la versión original no funcional para convertir a la versión funcional. También es mucho más conciso. Pero recuerde, muchos usuarios de Python se sentirán confundidos por la sintaxis lambda, por lo que lo que pierde en longitud y complejidad real podría recuperarse en la confusión de otros programadores.Limitaciones:
lambda
Las funciones solo se pueden usar una vez, a menos que se asignen a un nombre de variable.lambda
Las funciones asignadas a los nombres de las variables no tienen ventaja sobredef
funciones.lambda
Las funciones pueden ser difíciles o imposibles de eliminar.def
Los nombres de las funciones deben elegirse cuidadosamente para que sean razonablemente descriptivos y únicos o, al menos, no se utilicen en su alcance.Consistencia:
Python evita principalmente las convenciones de programación funcional a favor de una semántica objetiva más simple y de procedimiento. El
lambda
operador contrasta directamente con este sesgo. Además, como alternativa a la ya prevalentedef
, lalambda
función agrega diversidad a su sintaxis. Algunos lo considerarían menos consistente.Funciones preexistentes:
Como han señalado otros, muchos usos de
lambda
en el campo pueden ser reemplazados por miembros de losoperator
u otros módulos. Por ejemplo:El uso de la función preexistente puede hacer que el código sea más legible en muchos casos.
El principio pitónico: "Debe haber una, y preferiblemente solo una, forma obvia de hacerlo"
Eso es similar a la fuente única de la doctrina de la verdad . Desafortunadamente, el principio de una única forma obvia de hacerlo siempre ha sido más una aspiración nostálgica para Python que un verdadero principio rector. Considere las muy poderosas comprensiones de matrices en Python. Son funcionalmente equivalentes a las funciones
map
yfilter
:lambda
ydef
son iguales.Es una cuestión de opinión, pero yo diría que cualquier cosa en el lenguaje Python destinada al uso general que obviamente no rompa nada es suficientemente "Pythonic".
fuente
Hay una ventaja de usar una lambda sobre una función regular: se crean en una expresión.
Hay varios inconvenientes:
'<lambda>'
)También son ambos del mismo tipo de objeto. Por esas razones, generalmente prefiero crear funciones con la
def
palabra clave en lugar de con lambdas.Primer punto: son el mismo tipo de objeto
Una lambda da como resultado el mismo tipo de objeto que una función regular
Dado que las lambdas son funciones, son objetos de primera clase.
Ambas lambdas y funciones:
Pero a las lambdas, por defecto, les faltan algunas cosas que las funciones obtienen a través de la sintaxis de definición de función completa.
Un lamba
__name__
es'<lambda>'
Después de todo, las lambdas son funciones anónimas, por lo que no conocen su propio nombre.
Por lo tanto, los lambda no se pueden buscar programáticamente en su espacio de nombres.
Esto limita ciertas cosas. Por ejemplo,
foo
se puede buscar con código serializado, mientrasl
que no se puede:Podemos buscar
foo
bien, porque conoce su propio nombre:Las lambdas no tienen anotaciones ni cadenas de documentos
Básicamente, las lambdas no están documentadas. Reescribamos
foo
para estar mejor documentados:Ahora, foo tiene documentación:
Considerando que, no tenemos el mismo mecanismo para dar la misma información a las lambdas:
Pero podemos piratearlos en:
Sin embargo, probablemente haya algún error que arruine la salida de la ayuda.
Lambdas solo puede devolver una expresión
Las lambdas no pueden devolver declaraciones complejas, solo expresiones.
Es cierto que las expresiones pueden ser bastante complejas, y si se esfuerza mucho , probablemente pueda lograr lo mismo con una lambda, pero la complejidad adicional es más un detrimento para escribir código claro.
Usamos Python para mayor claridad y facilidad de mantenimiento. El uso excesivo de lambdas puede ir en contra de eso.
La única ventaja de las lambdas: se puede crear en una sola expresión
Esta es la única ventaja posible. Dado que puede crear una lambda con una expresión, puede crearla dentro de una llamada de función.
La creación de una función dentro de una llamada de función evita la búsqueda de nombre (económica) frente a una creada en otro lugar.
Sin embargo, dado que Python se evalúa estrictamente, no hay otra ganancia de rendimiento al hacerlo además de evitar la búsqueda de nombres.
Para una expresión muy simple, podría elegir una lambda.
También tiendo a usar lambdas cuando hago Python interactivo, para evitar múltiples líneas cuando una sirve. Utilizo el siguiente tipo de formato de código cuando quiero pasar un argumento a un constructor al llamar
timeit.repeat
:Y ahora:
Creo que la ligera diferencia de tiempo anterior se puede atribuir a la búsqueda de nombre en
return_nullary_function
; tenga en cuenta que es muy insignificante.Conclusión
Las lambdas son buenas para situaciones informales en las que desea minimizar las líneas de código a favor de hacer un punto singular.
Las lambdas son malas para situaciones más formales en las que se necesita claridad para los editores de código que vendrán más tarde, especialmente en los casos en que no son triviales.
Sabemos que se supone que debemos dar buenos nombres a nuestros objetos. ¿Cómo podemos hacerlo cuando el objeto no tiene nombre?
Por todas estas razones, generalmente prefiero crear funciones con en
def
lugar de conlambda
.fuente
Estoy de acuerdo con el consejo de nosklo: si necesitas darle un nombre a la función, usa
def
. Reservolambda
funciones para los casos en los que solo estoy pasando un breve fragmento de código a otra función, por ejemplo:fuente
Si bien está de acuerdo con las otras respuestas, a veces es más legible. He aquí un ejemplo en el que
lambda
viene muy bien, en un caso de uso sigo encontrando de una N dimensionesdefaultdict
.He aquí un ejemplo:
Lo encuentro más legible que crear un
def
para la segunda dimensión. Esto es aún más significativo para dimensiones superiores.fuente
from functools import partial; defaultdict(partial(defaultdict, list))
. Asigne el parcial a un nombre si desea usarlo más de una vez. Pero, si sigues encontrando esta construcción, significa que no estás SECO. Factorizarlo en una biblioteca de utilidades. Puede usar esta construcción para crear un defaultdict arbitrario n-dimensional usando otras funciones (o un bucle o recursividad).El uso principal de lambda siempre ha sido para funciones de devolución de llamada simples y para map, reduce, filter, que requieren una función como argumento. Con listas por comprensión que se convierten en la norma, y el agregado permitido si como en:
Es difícil imaginar un caso real para el uso de lambda en el uso diario. Como resultado, diría, evite lambda y cree funciones anidadas.
fuente
Una limitación importante de las lambdas es que no pueden contener nada más que una expresión. Es casi imposible que una expresión lambda produzca algo más que efectos secundarios triviales, ya que no puede tener un cuerpo tan rico como una
def
función ed.Dicho esto, Lua influyó en mi estilo de programación hacia el uso extensivo de funciones anónimas, y ensucio mi código con ellas. Además de eso, tiendo a pensar en map / reduce como operadores abstractos de maneras que no considero listas por comprensión o generadores, casi como si estuviera aplazando una decisión de implementación explícitamente usando esos operadores.
Editar: Esta es una pregunta bastante antigua, y mis opiniones sobre el tema han cambiado, un poco.
En primer lugar, estoy fuertemente predispuesto a no asignar una
lambda
expresión a una variable; ya que python tiene una sintaxis especial solo para eso (pista,def
). Además de eso, muchos de los usos de lambda, incluso cuando no reciben un nombre, tienen implementaciones predefinidas (y más eficientes). Por ejemplo, el ejemplo en cuestión se puede abreviar como just(1).__add__
, sin la necesidad de envolverlo enlambda
odef
. Muchos otros usos comunes pueden satisfacerse con alguna combinación de los módulosoperator
,itertools
yfunctools
.fuente
(1).__add__
- La llamada directa a métodos dunder casi nunca debería suceder. Millambda
s por cada llamada directa al dunder.(1).__add__
son algo poco comunes, pero no me acercaría a "debería". sin lugar a dudas, creo que el primero es mucho más legiblelambda x: 1 + x
. Si tuviéramos algo más parecido a la notación de corte de Haskells,(1+)
sería genial, pero tenemos que conformarnos con lo que semánticamente es exactamente eso, el nombre del método dunder.Considerando un simple ejemplo,
fuente
Si solo va a asignar la lambda a una variable en el ámbito local, también puede usar def porque es más legible y se puede expandir más fácilmente en el futuro:
o
fuente
from operator import pow;map(pow, someList)
y(a**b for a,b in someList)
son aún más legibles.Un uso para lambdas que he encontrado ... es en mensajes de depuración.
Dado que las lambdas se pueden evaluar de forma perezosa, puede tener un código como este:
en lugar de posiblemente caro:
que procesa la cadena de formato incluso si la llamada de depuración no produce salida debido al nivel de registro actual.
Por supuesto, para que funcione como se describe, el módulo de registro en uso debe admitir lambdas como "parámetros perezosos" (como lo hace mi módulo de registro).
La misma idea puede aplicarse a cualquier otro caso de evaluación perezosa para la creación de valor de contenido bajo demanda.
Por ejemplo, este operador ternario personalizado:
en vez de:
con lambdas solo se evaluará la expresión seleccionada por la condición, sin lambdas se evaluarán ambas.
Por supuesto, podría simplemente usar funciones en lugar de lambdas, pero para expresiones cortas, las lambdas son (c) más delgadas.
fuente
logging
ya tiene un formato diferido:log.debug("this is my message: %r", some_data)
solo formateará cuando / si se solicita el mensaje.some_data
podría ser una expresión costosa o una llamada a una función / método.Estoy de acuerdo con nosklo. Por cierto, incluso con un uso único, tírelo único , la mayoría de las veces solo desea usar algo del módulo del operador.
P.EJ :
Tiene una función con esta firma: myFunction (datos, función de devolución de llamada).
Quieres pasar una función que agregue 2 elementos.
Usando lambda:
La forma pitónica:
Por supuesto, este es un ejemplo simple, pero hay muchas cosas que proporciona el módulo de operador, incluidos los establecedores / captadores de elementos para lista y dic. Realmente genial.
fuente
Una diferencia importante es que no puede usar
def
funciones en línea, que es en mi opinión el caso de uso más conveniente para unalambda
función. Por ejemplo, al ordenar una lista de objetos:Por lo tanto, sugeriría mantener el uso de lambdas para este tipo de operaciones triviales, que tampoco se benefician realmente de la documentación automática proporcionada al nombrar la función.
fuente
lambda es útil para generar nuevas funciones:
fuente