E731 não atribua uma expressão lambda, use um def
Pergunta
Recebo esse aviso pep8 sempre que uso expressões lambda.As expressões lambda não são recomendadas?Se não, por que?
Solução
A recomendação em PEP-8 você está encontrando é:
Sempre use uma instrução DEF em vez de uma declaração de atribuição que vincule uma expressão lambda diretamente a um nome.
Sim:
def f(x): return 2*x
Não:
f = lambda x: 2*x
O primeiro formulário significa que o nome do objeto de função resultante é especificamente 'f' em vez do genérico 'u003Clambda> '.Isso é mais útil para rastreios e representações de cordas em geral.O uso da declaração de atribuição elimina o único benefício que uma expressão de lambda pode oferecer sobre uma declaração explícita de def (ou sejaque pode ser incorporado dentro de uma expressão maior)
Atribuir lambdas a nomes basicamente apenas duplica a funcionalidade de def
- e em geral, é melhor fazer algo de uma única maneira para evitar confusão e aumentar a clareza.
O caso de uso legítimo para lambda é onde você deseja usar uma função sem atribuí-la, por exemplo:
sorted(players, key=lambda player: player.rank)
Para operações simples, o operator
módulo fornece algumas opções úteis em attrgetter
, itemgetter
e methodcaller
que muitas vezes pode substituir labmdas que estão apenas acessando atributos, itens e métodos de chamada.
Por exemplo, o procedimento acima poderia ser feito com operator.attrgetter
igual a:
sorted(players, key=operator.attrgetter('rank'))
Outras dicas
Aqui está a história: eu tinha uma função lambda simples que usei duas vezes.
a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)
Isso é apenas para representação, já enfrentei algumas versões diferentes disso.
Agora, para manter as coisas SECAS, começo a reutilizar esse lambda comum.
f = lambda x : x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Neste ponto, meu verificador de qualidade de código reclama que lambda é uma função nomeada, então eu o converto em uma função.
def f(x):
return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Agora o verificador reclama que uma função deve ser delimitada por uma linha em branco antes e depois.
def f(x):
return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Aqui temos agora 6 linhas de código em vez das 2 linhas originais, sem aumento na legibilidade e sem aumento em pythônico.Neste ponto, o verificador de código reclama que a função não possui docstrings.
Na minha opinião, é melhor evitar e quebrar esta regra quando fizer sentido, use seu bom senso.
Lattyware está absolutamente certo:Basicamente PEP-8 quer que você evite coisas como
f = lambda x: 2 * x
e em vez disso use
def f(x):
return 2 * x
Contudo, conforme abordado em recente relatório de erro (agosto de 2014), declarações como as seguintes agora estão em conformidade:
a.f = lambda x: 2 * x
a["f"] = lambda x: 2 * x
Como meu verificador PEP-8 ainda não implementou isso corretamente, desliguei o E731 por enquanto.
Também encontrei uma situação em que era impossível usar uma função 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},
}
Nesse caso, eu queria muito fazer um mapeamento que pertencesse à classe.Alguns objetos no mapeamento precisavam da mesma função.Seria ilógico colocar a função nomeada fora da classe.Não encontrei uma maneira de me referir a um método (staticmethod, classmethod ou normal) de dentro do corpo da classe.SomeClass ainda não existe quando o código é executado.Portanto, referir-se a isso na classe também não é possível.