Ich versuche zu verstehen, was ist Affen-Patching oder ein Affen-Patch?
Ist das so etwas wie das Überladen oder Delegieren von Methoden / Operatoren?
Hat es etwas mit diesen Dingen gemeinsam?
Ich versuche zu verstehen, was ist Affen-Patching oder ein Affen-Patch?
Ist das so etwas wie das Überladen oder Delegieren von Methoden / Operatoren?
Hat es etwas mit diesen Dingen gemeinsam?
Antworten:
Nein, es ist nicht wie eines dieser Dinge. Es ist einfach das dynamische Ersetzen von Attributen zur Laufzeit.
Betrachten Sie beispielsweise eine Klasse mit einer Methode get_data
. Diese Methode führt eine externe Suche durch (z. B. in einer Datenbank oder einer Web-API), und verschiedene andere Methoden in der Klasse rufen sie auf. In einem Komponententest möchten Sie jedoch nicht von der externen Datenquelle abhängig sein. Daher ersetzen Sie die get_data
Methode dynamisch durch einen Stub, der einige feste Daten zurückgibt.
Da Python-Klassen veränderbar sind und Methoden nur Attribute der Klasse sind, können Sie dies beliebig tun - und sogar Klassen und Funktionen in einem Modul auf genau dieselbe Weise ersetzen.
Aber, wie ein Kommentator betonte, seien Sie beim Monkeypatching vorsichtig:
Wenn außer Ihren Testlogik-Aufrufen noch etwas anderes angezeigt wird get_data
, wird auch Ihr mit Affen gepatchter Ersatz anstelle des Originals aufgerufen - was gut oder schlecht sein kann. Pass auf dich auf.
Wenn eine Variable oder ein Attribut vorhanden ist, die bzw. get_data
das zum Zeitpunkt des Ersetzens auch auf die Funktion verweist, ändert dieser Alias seine Bedeutung nicht und verweist weiterhin auf das Original get_data
. (Warum? Python bindet den Namen get_data
in Ihrer Klasse nur an ein anderes Funktionsobjekt. Andere Namensbindungen sind davon überhaupt nicht betroffen.)
pointing to the original get_data function
? Meinen Sie, wenn Sie eine Funktion in einer Variablen speichern, wenn jemand diese Funktion ändert, zeigt die Variable weiterhin auf die alte?
get_data
ausführen, binden Sie den Namen erneut get_data
an eine Scheinfunktion . Wenn ein anderer Name an einer anderen Stelle im Programm an die Funktion gebunden ist, die früher als bekannt war get_data
, ändert sich für diesen anderen Namen nichts.
Ein MonkeyPatch ist ein Teil des Python-Codes, der zur Laufzeit (normalerweise beim Start) anderen Code erweitert oder ändert.
Ein einfaches Beispiel sieht so aus:
from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
return "ook ook eee eee eee!"
SomeClass.speak = speak
Quelle: MonkeyPatch- Seite im Zope-Wiki.
Was ist ein Affenfeld?
Einfach ausgedrückt, beim Affen-Patching werden Änderungen an einem Modul oder einer Klasse vorgenommen, während das Programm ausgeführt wird.
In der Pandas-Dokumentation finden Sie ein Beispiel für das Patchen von Affen:
import pandas as pd
def just_foo_cols(self):
"""Get a list of column names containing the string 'foo'
"""
return [x for x in self.columns if 'foo' in x]
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method
Um dies aufzuschlüsseln, importieren wir zuerst unser Modul:
import pandas as pd
Als nächstes erstellen wir eine Methodendefinition, die ungebunden und frei außerhalb des Bereichs von Klassendefinitionen existiert (da die Unterscheidung zwischen einer Funktion und einer ungebundenen Methode ziemlich bedeutungslos ist, beseitigt Python 3 die ungebundene Methode):
def just_foo_cols(self):
"""Get a list of column names containing the string 'foo'
"""
return [x for x in self.columns if 'foo' in x]
Als nächstes hängen wir diese Methode einfach an die Klasse an, für die wir sie verwenden möchten:
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
Und dann können wir die Methode für eine Instanz der Klasse verwenden und die Methode löschen, wenn wir fertig sind:
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method
Wenn Sie die Namensverknüpfung verwenden (indem Sie Attributen einen doppelten Unterstrich voranstellen, der den Namen ändert und den ich nicht empfehle), müssen Sie die Namensverknüpfung manuell durchführen, wenn Sie dies tun. Da ich das Mangeln von Namen nicht empfehle, werde ich es hier nicht demonstrieren.
Wie können wir dieses Wissen zum Beispiel beim Testen nutzen?
Angenommen, wir müssen einen Datenabrufaufruf an eine externe Datenquelle simulieren, der zu einem Fehler führt, da wir in einem solchen Fall ein korrektes Verhalten sicherstellen möchten. Wir können die Datenstruktur mit Affen patchen, um dieses Verhalten sicherzustellen. (Verwenden Sie also einen ähnlichen Methodennamen wie von Daniel Roseman vorgeschlagen :)
import datasource
def get_data(self):
'''monkey patch datasource.Structure with this to simulate error'''
raise datasource.DataRetrievalError
datasource.Structure.get_data = get_data
Und wenn wir es auf Verhalten testen, bei dem diese Methode einen Fehler auslöst, erhalten wir dieses Verhalten bei korrekter Implementierung in den Testergebnissen.
Structure
Wenn Sie nur die oben genannten Schritte ausführen, ändert sich das Objekt für die Dauer des Prozesses. Daher sollten Sie in Ihren Unittests Setups und Teardowns verwenden, um dies zu vermeiden, z.
def setUp(self):
# retain a pointer to the actual real method:
self.real_get_data = datasource.Structure.get_data
# monkey patch it:
datasource.Structure.get_data = get_data
def tearDown(self):
# give the real method back to the Structure object:
datasource.Structure.get_data = self.real_get_data
(Obwohl das oben Genannte in Ordnung ist, wäre es wahrscheinlich eine bessere Idee, die mock
Bibliothek zum Patchen des Codes zu verwenden. mock
Der patch
Dekorateur wäre weniger fehleranfällig als das oben Genannte, was mehr Codezeilen und damit mehr Möglichkeiten zur Einführung von Fehlern erfordern würde Ich habe den Code noch nicht überprüft, mock
aber ich stelle mir vor, dass er Affen-Patches auf ähnliche Weise verwendet.)
Laut Wikipedia :
In Python bezieht sich der Begriff "Affen-Patch" nur auf dynamische Änderungen einer Klasse oder eines Moduls zur Laufzeit, die durch die Absicht motiviert sind, vorhandenen Code von Drittanbietern zu patchen, um einen Fehler oder eine Funktion zu umgehen, die nicht wie gewünscht funktioniert.
Erstens: Das Patchen von Affen ist ein böser Hack (meiner Meinung nach).
Es wird häufig verwendet, um eine Methode auf Modul- oder Klassenebene durch eine benutzerdefinierte Implementierung zu ersetzen.
Der häufigste Anwendungsfall ist das Hinzufügen einer Problemumgehung für einen Fehler in einem Modul oder einer Klasse, wenn Sie den ursprünglichen Code nicht ersetzen können. In diesem Fall ersetzen Sie den "falschen" Code durch Affen-Patching durch eine Implementierung in Ihrem eigenen Modul / Paket.
Das Patchen von Affen kann nur in dynamischen Sprachen durchgeführt werden, wofür Python ein gutes Beispiel ist. Das Ändern einer Methode zur Laufzeit anstelle des Aktualisierens der Objektdefinition ist ein Beispiel. Ebenso wird das Hinzufügen von Attributen (ob Methoden oder Variablen) zur Laufzeit als Affen-Patching betrachtet. Diese werden häufig ausgeführt, wenn Sie mit Modulen arbeiten, für die Sie nicht die Quelle haben, sodass die Objektdefinitionen nicht einfach geändert werden können.
Dies wird als schlecht angesehen, da die Definition eines Objekts nicht vollständig oder genau beschreibt, wie es sich tatsächlich verhält.
Beim Affen-Patching werden die vorhandenen Klassen oder Methoden in der Klasse zur Laufzeit erneut geöffnet und das Verhalten geändert. Dies sollte mit Vorsicht angewendet werden, oder Sie sollten es nur verwenden, wenn Sie es wirklich benötigen.
Da Python eine dynamische Programmiersprache ist, können Klassen geändert werden, sodass Sie sie erneut öffnen und ändern oder sogar ersetzen können.
Was ist Affenpatching?Das Patchen von Affen ist eine Technik, mit der das Verhalten eines Codeteils zur Laufzeit dynamisch aktualisiert wird.
Warum Affenpatching verwenden?Es ermöglicht uns, das Verhalten von Bibliotheken, Modulen, Klassen oder Methoden zur Laufzeit zu ändern oder zu erweitern, ohne den Quellcode tatsächlich zu ändern
Fazit Das Patchen von Affen ist eine coole Technik, und jetzt haben wir gelernt, wie man das in Python macht. Wie wir bereits besprochen haben, hat es jedoch seine eigenen Nachteile und sollte sorgfältig verwendet werden.
Weitere Informationen finden Sie unter [1]: https://medium.com/@nagillavenkatesh1234/monkey-patching-in-python-explained-with-examples-25eed0aea505
Monkey patching is a technique to add, modify, or suppress the default behavior of a piece of code at runtime without changing its original source code.