E731 n’affecte pas une expression lambda, utilisez un def

J’obtiens cet avertissement pep8 chaque fois que j’utilise des expressions lambda. Les expressions lambda ne sont-elles pas recommandées? Sinon pourquoi?

La recommandation du PEP-8 que vous rencontrez est la suivante:

Utilisez toujours une instruction def au lieu d’une instruction d’affectation qui lie directement une expression lambda à un nom.

Oui:

def f(x): return 2*x 

Non:

 f = lambda x: 2*x 

La première forme signifie que le nom de l’object fonction résultant est spécifiquement «f» au lieu du nom générique «». Ceci est plus utile pour les traces et les représentations de chaînes en général. L’utilisation de l’instruction d’affectation élimine le seul avantage qu’une expression lambda peut offrir par rapport à une instruction def explicite (c’est-à-dire qu’elle peut être incorporée dans une expression plus grande)

Affecter des lambda à des noms ne fait que dupliquer les fonctionnalités de def – et en général, il est préférable de faire quelque chose d’une seule manière pour éviter toute confusion et pour plus de clarté.

Le cas d’utilisation légitime de lambda est l’endroit où vous souhaitez utiliser une fonction sans l’assigner, par exemple:

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

Pour les opérations simples, le module d’ operator fournit des options utiles dans attrgetter , itemgetter et methodcaller qui peuvent souvent remplacer les labmdas qui accèdent simplement à des atsortingbuts, des éléments et des méthodes d’appel.

Par exemple, ce qui précède pourrait être fait avec operator.attrgetter comme ceci:

 sorted(players, key=operator.attrgetter('rank')) 

Voici l’histoire, j’avais une simple fonction lambda que j’utilisais deux fois.

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

Ceci est juste pour la représentation, j’ai fait face à deux versions différentes de cela.

Maintenant, pour garder les choses au sec, je commence à réutiliser ce lambda commun.

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

À ce stade, mon vérificateur de qualité de code se plaint de ce que lambda soit une fonction nommée, alors je la convertis en fonction.

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

Maintenant, le vérificateur se plaint qu’une fonction doit être délimitée par une ligne vide avant et après.

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

Ici, nous avons maintenant 6 lignes de code au lieu de 2 lignes originales sans augmentation de la lisibilité et sans augmentation de la forme pythonique. À ce stade, le vérificateur de code se plaint de l’absence de docssortingngs sur la fonction.

À mon avis, cette règle devrait être évitée et brisée lorsque cela est logique, utilisez votre jugement.

Lattyware a tout à fait raison: en gros, PEP-8 veut que vous évitiez des choses comme

 f = lambda x: 2 * x 

et à la place utiliser

 def f(x): return 2 * x 

Cependant, comme indiqué dans un rapport de bogue récent (août 2014), les déclarations suivantes sont désormais conformes:

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

Étant donné que mon vérificateur PEP-8 ne l’a pas encore mis en œuvre correctement, j’ai désactivé E731 pour le moment.

J’ai également rencontré une situation dans laquelle il était même impossible d’utiliser une fonction 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}, } 

Dans ce cas, je voulais vraiment faire un mapping qui appartenait à la classe. Certains objects de la cartographie nécessitaient la même fonction. Il serait illogique de mettre une fonction nommée en dehors de la classe. Je n’ai pas trouvé de moyen de faire référence à une méthode (staticmethod, classmethod ou normal) à partir du corps de la classe. SomeClass n’existe pas encore lorsque le code est exécuté. Donc, faire référence à la classe n’est pas possible non plus.

Les Lambdas peuvent être utilisés pour des évaluations paresseuses, reportant ainsi certaines opérations coûteuses jusqu’à ce que leurs résultats soient réellement nécessaires.

Je viens de rencontrer un cas (sur un problème de concurrence / pratique du code) où je calculais des fonctions de pow () relativement coûteuses (relativement coûteuses, car l’entrée consistait en un demi-test) pour 3 cas différents et certaines combinaisons de cas Pour la clarté du code, je calculerais les 3 cas, puis renverrais la combinaison des 3 qui étaient réellement nécessaires pour la requête en cours.

Malheureusement, cela générait un TLE (“Time Limit dépassé”) sur certaines entrées.

En utilisant les lambdas pour différer les opérations coûteuses pow (), j’ai pu résoudre les problèmes TLE, car seuls les calculs pertinents pour la requête en cours étaient réellement invoqués.

Donc, je pense que c’est un cas où l’avertissement E731 n’est pas vraiment applicable et devrait être désactivé.