J'obtiens cet avertissement pep8 chaque fois que j'utilise des expressions lambda. Les expressions lambda ne sont-elles pas recommandées? Sinon pourquoi?
J'obtiens cet avertissement pep8 chaque fois que j'utilise des expressions lambda. Les expressions lambda ne sont-elles pas recommandées? Sinon pourquoi?
Réponses:
La recommandation dans PEP-8 que vous rencontrez est:
Utilisez toujours une instruction def au lieu d'une instruction d'affectation qui lie une expression lambda directement à 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 fonction résultant est spécifiquement «f» au lieu du générique «<lambda>». Ceci est plus utile pour les traces et les représentations sous forme 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 intégrée dans une expression plus grande)
L'attribution de lambdas à des noms ne fait que dupliquer la fonctionnalité de def
- et en général, il est préférable de faire quelque chose d'une seule manière pour éviter la confusion et augmenter la clarté.
Le cas d'utilisation légitime de lambda est celui où vous souhaitez utiliser une fonction sans l'affecter, par exemple:
sorted(players, key=lambda player: player.rank)
En général, le principal argument contre cela est que les def
instructions entraîneront plus de lignes de code. Ma principale réponse à cela serait: oui, et c'est très bien. À moins que vous ne codiez, minimiser le nombre de lignes n'est pas quelque chose que vous devriez faire: optez pour le clair plutôt que pour le court.
def
via le vérificateur PEP8, vous obtenez E704 multiple statements on one line (def)
, et si vous la divisez en deux lignes, vous obtenez E301 expected 1 blank line, found 0
: - /
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)
C'est juste pour la représentation, j'ai fait face à deux versions différentes de cela.
Maintenant, pour garder les choses 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 du fait que lambda est 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 vierge 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 du caractère pythonique. À ce stade, le vérificateur de code se plaint que la fonction n'a pas de docstrings.
À mon avis, il vaut mieux éviter et enfreindre cette règle lorsque cela a du sens, utilisez votre jugement.
a = [x + offset for x in simple_list]
. Pas besoin d'utiliser map
et lambda
ici.
x + offset
partie vers un emplacement abstrait qui peut être mis à jour sans changer plus d'une ligne de code. Avec les compréhensions de liste comme vous l'avez mentionné, vous auriez toujours besoin de deux lignes de code qui les contiendraient x + offset
juste maintenant dans les compréhensions de liste. Afin de les extraire comme l'auteur le voulait, vous auriez besoin d'un fichier def
ou lambda
.
def
et lambda
on pourrait aussi utiliser functools.partial : f = partial(operator.add, offset)
et puis a = list(map(f, simple_list))
.
def f(x): return x + offset
(c'est-à-dire une fonction simple définie sur une seule ligne)? Au moins avec flake8, je ne reçois pas de plaintes concernant les lignes vides.
a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
Lattyware a tout à fait raison: fondamentalement, PEP-8 veut que vous évitiez des choses comme
f = lambda x: 2 * x
et utilisez plutôt
def f(x):
return 2 * x
Cependant, comme indiqué dans un récent rapport de bogue (août 2014), des déclarations telles que les suivantes 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émente pas encore correctement, j'ai désactivé E731 pour le moment.
def
, le vérificateur PEP8 se plaint E301 expected 1 blank line, found 0
, vous devez donc ajouter une ligne vierge laide avant.
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 nécessitaient 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 (méthode statique, méthode de classe ou normale) depuis l'intérieur du corps de la classe. SomeClass n'existe pas encore lorsque le code est exécuté. Il n'est donc pas non plus possible de s'y référer depuis la classe.
also_not_reachable
dans la définition de mappage commeSomeClass.also_not_reachable
f
dans les versions 2.7 et 3.5 pour moi
@staticmethod
et @classmethod
n'ont pas besoin d'un objet, juste SomeClass.also_not_reachable
(bien qu'ils aient besoin de noms distinctifs). Si vous avez besoin d'y accéder à partir de méthodes de classe, utilisez simplementself.also_not_reachable
*not_reachable
méthodes en not_as_easily_reachable_from_class_definition_as_a_lambda
xD
flake8
( flake8.pycqa.org )