Ich erhalte diese pep8-Warnung, wenn ich Lambda-Ausdrücke verwende. Werden Lambda-Ausdrücke nicht empfohlen? Wenn nicht warum?
Ich erhalte diese pep8-Warnung, wenn ich Lambda-Ausdrücke verwende. Werden Lambda-Ausdrücke nicht empfohlen? Wenn nicht warum?
Antworten:
Die Empfehlung in PEP-8, auf die Sie stoßen, lautet:
Verwenden Sie immer eine def-Anweisung anstelle einer Zuweisungsanweisung, die einen Lambda-Ausdruck direkt an einen Namen bindet.
Ja:
def f(x): return 2*x
Nein:
f = lambda x: 2*x
Die erste Form bedeutet, dass der Name des resultierenden Funktionsobjekts spezifisch 'f' anstelle des generischen '<lambda>' ist. Dies ist im Allgemeinen für Tracebacks und Zeichenfolgendarstellungen nützlicher. Die Verwendung der Zuweisungsanweisung eliminiert den einzigen Vorteil, den ein Lambda-Ausdruck gegenüber einer expliziten def-Anweisung bieten kann (dh, dass er in einen größeren Ausdruck eingebettet werden kann).
Das Zuweisen von Lambdas zu Namen dupliziert im Grunde nur die Funktionalität von def
- und im Allgemeinen ist es am besten, etwas auf eine einzige Weise zu tun, um Verwirrung zu vermeiden und die Klarheit zu erhöhen.
Der legitime Anwendungsfall für Lambda ist, wenn Sie eine Funktion verwenden möchten, ohne sie zuzuweisen, z.
sorted(players, key=lambda player: player.rank)
Im Allgemeinen ist das Hauptargument dagegen, dass def
Anweisungen zu mehr Codezeilen führen. Meine Hauptantwort darauf wäre: Ja, und das ist in Ordnung. Wenn Sie nicht Code-Golf spielen, sollten Sie die Anzahl der Linien nicht minimieren: Gehen Sie klar über kurz.
def
durch den PEP8-Checker ausführen, erhalten Sie E704 multiple statements on one line (def)
, und wenn Sie ihn in zwei Zeilen aufteilen, erhalten Sie E301 expected 1 blank line, found 0
: - /
Hier ist die Geschichte, ich hatte eine einfache Lambda-Funktion, die ich zweimal benutzte.
a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)
Dies ist nur für die Darstellung, ich habe einige verschiedene Versionen davon konfrontiert.
Um die Dinge trocken zu halten, beginne ich, dieses gewöhnliche Lambda wiederzuverwenden.
f = lambda x : x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
An diesem Punkt beschwert sich mein Codequalitätsprüfer darüber, dass Lambda eine benannte Funktion ist, also konvertiere ich es in eine Funktion.
def f(x):
return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Jetzt beschwert sich der Prüfer, dass eine Funktion vorher und nachher durch eine Leerzeile begrenzt werden muss.
def f(x):
return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Hier haben wir jetzt 6 Codezeilen anstelle der ursprünglichen 2 Zeilen ohne Erhöhung der Lesbarkeit und ohne Erhöhung der Python. Zu diesem Zeitpunkt beschwert sich die Codeprüfung über die Funktion ohne Dokumentzeichenfolgen.
Meiner Meinung nach sollte diese Regel besser vermieden und gebrochen werden, wenn es Sinn macht. Verwenden Sie Ihr Urteilsvermögen.
a = [x + offset for x in simple_list]
. Keine Notwendigkeit zu verwenden map
und lambda
hier.
x + offset
Teil an einen abstrahierten Ort zu verschieben, der aktualisiert werden kann, ohne mehr als eine Codezeile zu ändern. Bei Listenverständnissen, wie Sie bereits erwähnt haben, benötigen Sie noch zwei Codezeilen, die enthalten sind, dass x + offset
sie sich gerade in Listenverständnissen befinden. Um diese nach Wunsch des Autors herauszuziehen, benötigen Sie ein def
oder lambda
.
def
und lambda
man könnte auch functools.partial verwenden : f = partial(operator.add, offset)
und dann a = list(map(f, simple_list))
.
def f(x): return x + offset
(dh einer einfachen Funktion, die in einer einzelnen Zeile definiert ist)? Zumindest mit flake8 bekomme ich keine Beschwerden über Leerzeilen.
a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
Lattyware ist absolut richtig: Grundsätzlich möchte PEP-8, dass Sie Dinge wie vermeiden
f = lambda x: 2 * x
und stattdessen verwenden
def f(x):
return 2 * x
Wie in einem kürzlich veröffentlichten Bugreport (August 2014) angesprochen , sind Aussagen wie die folgenden nun konform:
a.f = lambda x: 2 * x
a["f"] = lambda x: 2 * x
Da mein PEP-8-Checker dies noch nicht korrekt implementiert, habe ich E731 vorerst ausgeschaltet.
def
beschwert sich der PEP8-Checker bei E301 expected 1 blank line, found 0
, sodass Sie davor eine hässliche Leerzeile einfügen müssen.
Ich bin auch auf eine Situation gestoßen, in der es sogar unmöglich war, eine def (ined) -Funktion zu verwenden.
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},
}
In diesem Fall wollte ich unbedingt ein Mapping erstellen, das zur Klasse gehört. Einige Objekte in der Zuordnung benötigten dieselbe Funktion. Es wäre unlogisch, die benannte Funktion außerhalb der Klasse zu platzieren. Ich habe keine Möglichkeit gefunden, innerhalb des Klassenkörpers auf eine Methode (statische Methode, Klassenmethode oder normal) zu verweisen. SomeClass existiert noch nicht, wenn der Code ausgeführt wird. Es ist also auch nicht möglich, sich aus der Klasse darauf zu beziehen.
also_not_reachable
in der Mapping-Definition alsSomeClass.also_not_reachable
f
für mich so erreichbar wie in 2.7 und 3.5
@staticmethod
und @classmethod
ohne Objekt, nur SomeClass.also_not_reachable
(obwohl sie eindeutige Namen benötigen). Wenn Sie über Klassenmethoden auf sie zugreifen müssen, verwenden Sie einfachself.also_not_reachable
*not_reachable
Methoden in not_as_easily_reachable_from_class_definition_as_a_lambda
xD umbenennen
flake8
( flake8.pycqa.org )