web-dev-qa-db-fra.com

E731 ne pas attribuer une expression lambda, utiliser un def

Je reçois cet avertissement pep8 chaque fois que j'utilise des expressions lambda. Les expressions lambda ne sont-elles pas recommandées? Si non pourquoi

167
Kechit Goyal

La recommandation dans 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'objet de fonction résultant est spécifiquement "f" au lieu du générique "<lambda>". Ceci est plus utile pour les retraits de trace et les représentations de chaîne 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).

L'attribution de lambdas à 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 façon pour éviter la confusion et améliorer la clarté.

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

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

Pour les opérations simples, le module operator fournit des options utiles dans attrgetter , itemgetter et methodcaller qui peuvent souvent remplacer les labmdas qui n’accèdent qu’à un attribut ( s), article (s) et méthodes d'appel.

Par exemple, ce qui précède pourrait être réalisé avec operator.attrgetter comme suit:

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

Voici l’histoire, j’avais une fonction lambda simple 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 la qualité du code se plaint que lambda soit une fonction nommée, je la convertis donc 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)

Nous avons maintenant 6 lignes de code au lieu de 2 lignes originales sans augmentation de lisibilité ni augmentation de Pythonic. À ce stade, le vérificateur de code se plaint de l'absence de docstrings dans la fonction.

À mon avis, il vaut mieux éviter et déroger à cette règle quand elle a du sens, utilisez votre jugement.

98
iankit

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 récent rapport de bogue (août 2014), des déclarations telles que celles qui suivent sont désormais conformes:

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

Étant donné que mon vérificateur PEP-8 ne l'implémentait pas correctement, j'ai désactivé le E731 pour le moment.

21
Elmar Peise

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 objets du mappage avaient besoin de la même fonction. Il serait illogique de placer la 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) depuis l'intérieur du corps de la classe. SomeClass n’existe pas encore à l’exécution du code. Il n'est donc pas possible d'y faire référence en classe.

2
simP