Welche Funktionalität functools.partial
bietet Sie, die Sie nicht durch Lambdas bekommen können?
Nicht viel an zusätzlicher Funktionalität (siehe später) - und die Lesbarkeit liegt im Auge des Betrachters.
Die meisten Leute, die mit funktionalen Programmiersprachen vertraut sind (insbesondere die in den Lisp / Scheme-Familien), scheinen es gut zu mögen lambda
- ich sage "die meisten", definitiv nicht alle, weil Guido und ich sicherlich zu denen gehören, die "vertraut sind" (etc. ) dennoch lambda
als Schandfleck-Anomalie in Python betrachten ...
Er bereute es, es jemals in Python akzeptiert zu haben, während er vorhatte, es aus Python 3 zu entfernen, als eine von "Pythons Pannen".
Ich habe ihn dabei voll unterstützt. (Ich liebe lambda
in Scheme ... während seine Einschränkungen in Python und die seltsame Art und Weise, wie es einfach nicht funktioniert. mit dem Rest der Sprache meine Haut kriechen lassen).
Nicht so jedoch für die Horden von lambda
Liebhabern - der als einer der engstenen Dinge zu einem Aufstand inszeniert jemals in Python Geschichte gesehen, bis Guido Rückzieher und beschlossen , zu verlassen lambda
. In
mehr möglichen Ergänzungen functools
(um Funktionen Rückkehr Konstanten, Identität, etc) ist nicht aufgetreten (um zu vermeiden, dass mehr lambda
Funktionen explizit dupliziert werden ), ist partial
aber natürlich geblieben (es ist keine vollständige Duplizierung, noch ist es ein Dorn im Auge).
Denken Sie daran, dass lambda
der Körper nur ein Ausdruck sein kann , daher gibt es Einschränkungen. Beispielsweise...:
>>> import functools
>>> f = functools.partial(int, base=2)
>>> f.args
()
>>> f.func
<type 'int'>
>>> f.keywords
{'base': 2}
>>>
functools.partial
Die zurückgegebene Funktion ist mit Attributen versehen, die für die Selbstbeobachtung nützlich sind - der Funktion, die sie umschließt, und den darin festgelegten positionellen und benannten Argumenten. Darüber hinaus können die genannten Argumente sofort wieder überschrieben werden (die "Korrektur" ist in gewissem Sinne eher die Einstellung von Standardeinstellungen):
>>> f('23', base=10)
23
Wie Sie sehen, ist es definitiv nicht so einfach wie lambda s: int(s, base=2)
! -)
Ja, Sie könnten Ihr Lambda verzerren, um Ihnen etwas davon zu geben - z. B. für das Überschreiben von Schlüsselwörtern,
>>> f = lambda s, **k: int(s, **dict({'base': 2}, **k))
aber ich hoffe sehr , dass selbst der leidenschaftlichste lambda
Liebhaber diesen Horror nicht lesbarer findet als den partial
Anruf! -). Der Teil "Attributeinstellung" ist noch schwieriger, da die Einschränkung "Python ist ein einzelner Ausdruck" von Python lambda
(plus die Tatsache, dass die Zuweisung niemals Teil eines Python-Ausdrucks sein kann) ... Sie am Ende "Zuweisungen innerhalb eines Ausdrucks vortäuschen". durch Ausdehnung des Listenverständnisses weit über seine Designgrenzen hinaus ...:
>>> f = [f for f in (lambda f: int(s, base=2),)
if setattr(f, 'keywords', {'base': 2}) is None][0]
Kombinieren Sie nun die Überschreibbarkeit der benannten Argumente sowie die Einstellung von drei Attributen in einem einzigen Ausdruck und sagen Sie mir, wie lesbar das sein wird ...!
functools.partial
, die Sie erwähnt haben, Lambda überlegen macht. Vielleicht ist dies das Thema eines anderen Beitrags, aber was stört Sie auf Designebene so sehrlambda
?def
undlambda
Schlüsselwort: Machen Sie beidefunction
(eine Namenswahl, die Javascript wirklich richtig gemacht hat), und mindestens 1/3 meiner Einwände würde verschwinden ! -). Wie gesagt, ich habe keine Einwände gegen Lambda in Lisp ...! -)def
sowieso eine verwenden können. Unser gütiger Führer hat gesprochen!Hier ist ein Beispiel, das einen Unterschied zeigt:
Diese Beiträge von Ivan Moore erweitern die "Einschränkungen von Lambda" und Verschlüsse in Python:
quelle
lambda y, n=n: ...
. Eine späte Bindung (von Namen, die nur im Körper einer Funktion erscheinen, nicht in ihremdef
oder einem gleichwertigenlambda
) ist alles andere als ein Fehler, wie ich in langen SO-Antworten in der Vergangenheit ausführlich gezeigt habe: Sie binden explizit früh, wenn Sie dies wünschen. verwenden Sie die späte Bindung standardmäßig , wenn das ist , was Sie wollen, und das ist genau die richtige Design Wahl des Kontext des Restes von Python-Design gegeben.In den neuesten Versionen von Python (> = 2.7) können Sie
pickle
apartial
, aber nicht alambda
:quelle
multiprocessing.Pool.map()
. stackoverflow.com/a/3637905/195139partial
Er kann in Python 2.7 ausgewählt werden.Als teilweise Antwort darauf habe ich beschlossen, die Leistung zu testen. Hier ist mein Beispiel:
unter Python 3.3 gibt es:
Dies bedeutet, dass Partial etwas mehr Zeit für die Erstellung benötigt, aber erheblich weniger Zeit für die Ausführung. Dies kann durchaus der Effekt der frühen und späten Bindung sein, die in der Antwort von ars diskutiert werden .
quelle
partial
ist, dass es in C geschrieben ist und nicht in reinem Python, was bedeutet, dass es einen effizienteren Aufruf erzeugen kann, als einfach eine Funktion zu erstellen, die eine andere Funktion aufruft.Neben der von Alex erwähnten zusätzlichen Funktionalität ist ein weiterer Vorteil von functools.partial die Geschwindigkeit. Mit partiell können Sie vermeiden, einen anderen Stapelrahmen zu konstruieren (und zu zerstören).
Weder die von partiellen noch von Lambdas generierte Funktion verfügt standardmäßig über Dokumentzeichenfolgen (obwohl Sie die Dokumentzeichenfolge für alle Objekte über festlegen können
__doc__
).Weitere Details finden Sie in diesem Blog: Partial Function Application in Python
quelle
Ich verstehe die Absicht im dritten Beispiel am schnellsten.
Wenn ich Lambdas analysiere, erwarte ich mehr Komplexität / Seltsamkeit als von der Standardbibliothek direkt angeboten.
Außerdem werden Sie feststellen, dass das dritte Beispiel das einzige ist, das nicht von der vollständigen Signatur von abhängt
sum2
. Dadurch wird es etwas lockerer gekoppelt.quelle
functools.partial
Anruf zu analysieren , während die Lambdas selbstverständlich sind.