Tut ungefähr partial
so etwas (abgesehen von der Unterstützung von Keyword-Argumenten usw.):
def partial(func, *part_args):
def wrapper(*extra_args):
args = list(part_args)
args.extend(extra_args)
return func(*args)
return wrapper
Wenn partial(sum2, 4)
Sie also aufrufen , erstellen Sie eine neue Funktion (genauer gesagt eine aufrufbare), die sich wie verhält sum2
, aber ein Positionsargument weniger hat. Dieses fehlende Argument wird immer durch ersetzt 4
, so dasspartial(sum2, 4)(2) == sum2(4, 2)
Es gibt verschiedene Fälle, warum es benötigt wird. Angenommen, Sie müssen eine Funktion an einer Stelle übergeben, an der zwei Argumente erwartet werden:
class EventNotifier(object):
def __init__(self):
self._listeners = []
def add_listener(self, callback):
''' callback should accept two positional arguments, event and params '''
self._listeners.append(callback)
# ...
def notify(self, event, *params):
for f in self._listeners:
f(event, params)
Eine Funktion, die Sie bereits haben, benötigt jedoch Zugriff auf ein drittes context
Objekt, um ihre Aufgabe zu erfüllen :
def log_event(context, event, params):
context.log_event("Something happened %s, %s", event, params)
Es gibt also mehrere Lösungen:
Ein benutzerdefiniertes Objekt:
class Listener(object):
def __init__(self, context):
self._context = context
def __call__(self, event, params):
self._context.log_event("Something happened %s, %s", event, params)
notifier.add_listener(Listener(context))
Lambda:
log_listener = lambda event, params: log_event(context, event, params)
notifier.add_listener(log_listener)
Mit Teiltönen:
context = get_context() # whatever
notifier.add_listener(partial(log_event, context))
Von diesen dreien partial
ist es das kürzeste und das schnellste. (Für einen komplexeren Fall möchten Sie möglicherweise ein benutzerdefiniertes Objekt.)
extra_args
extra_args
ist etwas , das in dem Beispiel durch die partiellen Anrufer, geleitet , die mitp = partial(func, 1); f(2, 3, 4)
er ist(2, 3, 4)
.callback
undmy_callback
Partials sind unglaublich nützlich.
Zum Beispiel in einer 'Pipeline'-Folge von Funktionsaufrufen (in der der von einer Funktion zurückgegebene Wert das an die nächste übergebene Argument ist).
Manchmal erfordert eine Funktion in einer solchen Pipeline ein einzelnes Argument , aber die unmittelbar vorgelagerte Funktion gibt zwei Werte zurück .
In diesem Szenario
functools.partial
können Sie diese Funktionspipeline möglicherweise intakt halten.Hier ist ein spezielles, isoliertes Beispiel: Angenommen, Sie möchten einige Daten nach der Entfernung jedes Datenpunkts von einem Ziel sortieren:
Um diese Daten nach Entfernung vom Ziel zu sortieren, möchten Sie natürlich Folgendes tun:
aber du nicht - die Art der Methode Schlüsselparameter nur Funktionen übernehmen , die einen nehmen einzelnes Argument.
Schreiben Sie also
euclid_dist
als Funktion neu, indem Sie einen einzelnen Parameter verwenden:p_euclid_dist
akzeptiert jetzt ein einziges Argument,Jetzt können Sie Ihre Daten sortieren, indem Sie die Teilfunktion für das Schlüsselargument der Sortiermethode übergeben:
Zum Beispiel ändert sich eines der Argumente der Funktion in einer äußeren Schleife, wird jedoch während der Iteration in der inneren Schleife festgelegt. Bei Verwendung eines Teils müssen Sie den zusätzlichen Parameter während der Iteration der inneren Schleife nicht übergeben, da die modifizierte (Teil-) Funktion dies nicht erfordert.
Erstellen Sie eine Teilfunktion (mit dem Schlüsselwort arg)
Sie können auch eine Teilfunktion mit einem Positionsargument erstellen
Dies wird jedoch ausgelöst (z. B. Erstellen eines Teils mit einem Schlüsselwortargument und anschließendes Aufrufen mit Positionsargumenten).
Ein weiterer Anwendungsfall: Schreiben von verteiltem Code mithilfe der Python-
multiprocessing
Bibliothek. Ein Pool von Prozessen wird mit der Pool-Methode erstellt:Pool
hat eine Map-Methode, benötigt aber nur eine einzige iterable. Wenn Sie also eine Funktion mit einer längeren Parameterliste übergeben müssen, definieren Sie die Funktion als Teil neu, um alle bis auf eine zu reparieren:quelle
Kurze Antwort:
partial
Gibt den Parametern einer Funktion Standardwerte, die sonst keine Standardwerte hätten.quelle
partial
und so weiterPartials können verwendet werden, um neue abgeleitete Funktionen zu erstellen, denen einige Eingabeparameter vorab zugewiesen wurden
Informationen zur Verwendung von Partials in der Praxis finden Sie in diesem wirklich guten Blog-Beitrag:
http://chriskiehl.com/article/Cleaner-coding-through-partially-applied-functions/
Eine einfache , aber ordentlich Anfänger Beispiel aus dem Blog, Abdeckungen , wie man verwenden könnte ,
partial
aufre.search
Code besser lesbar zu machen.re.search
Die Signatur der Methode lautet:Durch Anwenden können
partial
wir mehrere Versionen des regulären Ausdrucks erstellensearch
, um unseren Anforderungen zu entsprechen, zum Beispiel:Nun
is_spaced_apart
undis_grouped_together
sind zwei neue Funktionen abgeleitet, vonre.search
denen daspattern
Argument angewendet wurde (da diespattern
das erste Argument in derre.search
Signatur der Methode ist).Die Signatur dieser beiden neuen Funktionen (aufrufbar) lautet:
So können Sie dann diese Teilfunktionen für einen Text verwenden:
Sie können auf den obigen Link verweisen , um ein tieferes Verständnis des Themas zu erhalten, da es dieses spezielle Beispiel und vieles mehr abdeckt.
quelle
is_spaced_apart = re.compile('[a-zA-Z]\s\=').search
? Wenn ja, gibt es eine Garantie dafür, dass daspartial
Idiom den regulären Ausdruck für eine schnellere Wiederverwendung kompiliert?Meiner Meinung nach ist es eine Möglichkeit, Currying in Python zu implementieren .
Das Ergebnis ist 3 und 4.
quelle
Erwähnenswert ist auch, dass, wenn eine Teilfunktion eine andere Funktion übergeben hat, bei der einige Parameter "hart codiert" werden sollen, dies der Parameter ganz rechts sein sollte
aber wenn wir das gleiche tun, aber stattdessen einen Parameter ändern
es wird der Fehler "TypeError: func () hat mehrere Werte für das Argument 'a'" ausgelöst.
quelle
prt=partial(func, 7)
Diese Antwort ist eher ein Beispielcode. Alle obigen Antworten geben gute Erklärungen, warum man teilweise verwenden sollte. Ich werde meine Beobachtungen und Anwendungsfälle über teilweise geben.
Die Ausgabe des obigen Codes sollte sein:
Beachten Sie, dass im obigen Beispiel eine neue aufrufbare Datei zurückgegeben wurde, die den Parameter (c) als Argument verwendet. Beachten Sie, dass dies auch das letzte Argument für die Funktion ist.
Die Ausgabe des obigen Codes ist auch:
Beachten Sie, dass * zum Entpacken der Nicht-Schlüsselwort-Argumente verwendet wurde und der zurückgegebene Aufruf in Bezug auf das Argument, das er verwenden kann, dasselbe wie oben ist.
Eine weitere Beobachtung ist: Das folgende Beispiel zeigt, dass ein Teil einen aufrufbaren Wert zurückgibt, der den nicht deklarierten Parameter (a) als Argument verwendet.
Die Ausgabe des obigen Codes sollte sein:
Ähnlich,
Der obige Code wird gedruckt
Ich musste es verwenden, als ich die
Pool.map_async
Methode aus demmultiprocessing
Modul verwendete. Sie können nur ein Argument an die Worker-Funktion übergeben, sodass ichpartial
meine Worker-Funktion wie eine aufrufbare Funktion mit nur einem Eingabeargument aussehen lassen musste. In Wirklichkeit hatte meine Worker-Funktion jedoch mehrere Eingabeargumente.quelle