Recibo esta advertencia pep8 cada vez que uso expresiones lambda. ¿No se recomiendan las expresiones lambda? Si no, ¿por qué?
Recibo esta advertencia pep8 cada vez que uso expresiones lambda. ¿No se recomiendan las expresiones lambda? Si no, ¿por qué?
Respuestas:
La recomendación en PEP-8 con la que se encuentra es:
Utilice siempre una instrucción def en lugar de una instrucción de asignación que vincule una expresión lambda directamente a un nombre.
Si:
def f(x): return 2*x
No:
f = lambda x: 2*x
La primera forma significa que el nombre del objeto de función resultante es específicamente 'f' en lugar del genérico '<lambda>'. Esto es más útil para trazas y representaciones de cadenas en general. El uso de la declaración de asignación elimina el único beneficio que puede ofrecer una expresión lambda sobre una declaración def explícita (es decir, que se puede incrustar dentro de una expresión más grande)
Asignar lambdas a nombres básicamente 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 utilizar una función sin asignarla, por ejemplo:
sorted(players, key=lambda player: player.rank)
En general, el argumento principal en contra de hacer esto es que las def
declaraciones generarán más líneas de código. Mi respuesta principal a eso sería: sí, y eso está bien. A menos que esté jugando golf de códigos, minimizar el número de líneas no es algo que deba hacer: vaya para despejar en corto.
def
través del verificador PEP8, obtienes E704 multiple statements on one line (def)
, y si lo divides en dos líneas obtienes E301 expected 1 blank line, found 0
: - /
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 verificador 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 verificador se queja de que una función tiene que estar delimitada 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 verificador 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 tenga sentido, use su criterio.
a = [x + offset for x in simple_list]
. No es necesario usar map
y lambda
aquí.
x + offset
porción a una ubicación abstracta que se puede actualizar sin cambiar más de una línea de código. Con las comprensiones de listas como mencionó, aún necesitaría dos líneas de código que contuvieran x + offset
, ahora estarían en comprensiones de listas. Para sacarlos como el autor quería, necesitaría una def
o lambda
.
def
y lambda
uno también podría usar functools.partial : f = partial(operator.add, offset)
y luego a = list(map(f, simple_list))
.
def f(x): return x + offset
(es decir, una función simple definida en una sola línea)? Al menos con flake8 no recibo quejas sobre líneas en blanco.
a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
Lattyware tiene toda la razón: básicamente, PEP-8 quiere que evites cosas como
f = lambda x: 2 * x
y en su lugar usar
def f(x):
return 2 * x
Sin embargo, como se abordó en un informe reciente de errores (agosto de 2014), declaraciones como las siguientes ahora son compatibles:
a.f = lambda x: 2 * x
a["f"] = lambda x: 2 * x
Como mi corrector PEP-8 todavía no lo implementa correctamente, apagué E731 por el momento.
def
, el corrector PEP8 se queja E301 expected 1 blank line, found 0
, por lo que debe agregar una línea en blanco fea antes.
También me encontré con una situación en la que incluso era 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 un mapeo que perteneciera a la clase. Algunos objetos en el mapeo necesitaban la misma función. Sería ilógico colocar una función con nombre fuera de la clase. No he encontrado una manera de referirme a un método (método estático, método de clase o normal) desde el interior del cuerpo de la clase. SomeClass aún no existe cuando se ejecuta el código. Entonces, referirse a él desde la clase tampoco es posible.
also_not_reachable
en la definición de mapeo comoSomeClass.also_not_reachable
f
en 2.7 y 3.5 para mí
@staticmethod
y @classmethod
no necesitan un objeto, solo SomeClass.also_not_reachable
(aunque necesitan nombres distintivos). Si necesita acceder a ellos desde los métodos de clase, simplemente useself.also_not_reachable
*not_reachable
métodos como not_as_easily_reachable_from_class_definition_as_a_lambda
xD
flake8
( flake8.pycqa.org )