E731 no asignar una expresión lambda, utilizar un def


Recibo esta advertencia pep8 cada vez que uso expresiones lambda. ¿No se recomiendan las expresiones lambda? Si no ¿por qué?

Author: Kechit Goyal, 2014-07-29

5 answers

La recomendación en PEP-8 que se encuentra es:

Utilice siempre una instrucción def en lugar de una instrucción assignment que vincula una expresión lambda directamente a un nombre.

Sí:

def f(x): return 2*x 

No:

f = lambda x: 2*x 

La primera forma significa que el nombre de la el objeto de función es específicamente ' f 'en lugar del genérico' '. Esto es más útil para tracebacks y representaciones de cadenas en general. El uso de la declaración de asignación elimina el único beneficio que una expresión lambda puede ofrecer sobre una declaración def explícita (i. e. that it can be embedded inside a larger expression)

Asignar lambdas a nombres básicamente solo duplica la funcionalidad de def - y en general, es mejor hacer algo de una sola manera para evitar confusiones y aumentar la claridad.

El caso de uso legítimo para lambda es donde desea usar una función sin asignarla, por ejemplo:

sorted(players, key=lambda player: player.rank)

Para operaciones simples, el módulo operator proporciona algunas opciones útiles en attrgetter, itemgetter y methodcaller que a menudo puede reemplazar a los labmda que solo acceden a atributos, elementos y métodos de llamada.

Por ejemplo, lo anterior podría hacerse con operator.attrgetter así:

sorted(players, key=operator.attrgetter('rank'))
 150
Author: Gareth Latty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-06 19:33:32

Aquí está la historia, tenía una función lambda simple que estaba usando dos veces.

a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)

Esto es solo para la representación, me he enfrentado a un par de versiones diferentes de esto.

Ahora, para mantener las cosas SECAS, empiezo a reutilizar esta lambda común.

f = lambda x : x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)

En este punto, mi comprobador de calidad de código se queja de que lambda es una función con nombre, por lo que la convierto en una función.

def f(x):
    return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)

Ahora el comprobador se queja de que una función tiene que estar limitada por una línea en blanco antes y después.

def f(x):
    return x + offset

a = map(f, simple_list)
b = map(f, another_simple_list)

Aquí tenemos ahora 6 líneas de código en lugar de las 2 líneas originales sin aumento en la legibilidad y sin aumento en ser pitónico. En este punto, el comprobador de código se queja de que la función no tiene cadenas de documentos.

En mi opinión, es mejor evitar y romper esta regla cuando tiene sentido, use su juicio.

 73
Author: iankit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-09 18:19:58

Lattyware tiene toda la razón: Básicamente PEP-8 quiere que evite cosas como

f = lambda x: 2 * x

Y en su lugar use

def f(x):
    return 2 * x

Sin embargo, como se abordó en un informe de error reciente (Ago 2014), declaraciones como las siguientes ahora son compatibles:

a.f = lambda x: 2 * x
a["f"] = lambda x: 2 * x

Dado que mi comprobador PEP-8 no implementa esto correctamente todavía, desactivé E731 por el momento.

 18
Author: Elmar Peise,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-13 17:32:28

También me encontré con una situación en la que era incluso imposible usar una función def(ined).

class SomeClass(object):
  # pep-8 does not allow this
  f = lambda x: x + 1  # NOQA

  def not_reachable(self, x):
    return x + 1

  @staticmethod
  def also_not_reachable(x):
    return x + 1

  @classmethod
  def also_not_reachable(cls, x):
    return x + 1

  some_mapping = {
      'object1': {'name': "Object 1", 'func': f},
      'object2': {'name': "Object 2", 'func': some_other_func},
  }

En este caso, realmente quería hacer una asignación que perteneciera a la clase. Algunos objetos de la asignación necesitaban la misma función. Sería ilógico poner la función con nombre a fuera de la clase. No he encontrado una manera de hacer referencia a un método (staticmethod, classmethod o normal) desde dentro del cuerpo de la clase. SomeClass no existe todavía cuando se ejecuta el código. Así que refiriéndose a desde la clase tampoco es posible.

 2
Author: simP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-16 14:12:36

Las lambdas se pueden usar para evaluaciones perezosas, aplazando así ciertas operaciones costosas hasta que sus resultados sean realmente necesarios.

Me encontré con un caso (en un problema de competencia/práctica de código) donde estaba computando funciones pow() relativamente caras (relativamente caras, ya que la entrada consistía en medio millón de casos de prueba) para 3 casos diferentes y ciertas combinaciones de los 3 casos. Para la claridad del código, computaría los 3 casos y luego devolvería la combinación de los 3 eso era realmente necesario para la solicitud actual.

Desafortunadamente, esto estaba generando un TLE ("límite de tiempo excedido") en ciertas entradas.

Al usar las lambdas para diferir las costosas operaciones pow (), pude resolver problemas TLE, ya que solo se invocaron los cálculos que eran relevantes para la solicitud actual.

Así que creo que este es un caso en el que la advertencia E731 no es realmente aplicable y debería desactivarse..

 -1
Author: Gino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-02 11:07:51