it-swarm.com.de

Was ist Affenpatching?

Ich versuche zu verstehen, was ist Affen-Patching oder ein Affen-Patch?

Überladen oder delegieren das so etwas wie Methoden/Operatoren?

Hat es mit diesen Dingen etwas gemeinsam?

479
Sergei Basharov

Nein, es ist nicht so. 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 wird von verschiedenen anderen Methoden in der Klasse aufgerufen. In einem Komponententest möchten Sie jedoch nicht von der externen Datenquelle abhängig sein. Ersetzen Sie daher die Methode get_data 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 nach Belieben tun - und sogar Klassen und Funktionen in einem Modul in ersetzen genau so.

Aber als Kommentator wies darauf hin, seien Sie vorsichtig beim Monkeypatching:

  1. Wenn etwas anderes als Ihre Testlogik auch get_data Aufruft, ruft es auch Ihren mit Affen gepatchten Ersatz auf und nicht das Original - was gut oder schlecht sein kann. Passen Sie einfach auf.

  2. Wenn eine Variable oder ein Attribut vorhanden ist, die bzw. das zum Zeitpunkt des Ersetzens auf die Funktion get_data Verweist, ändert dieser Alias ​​seine Bedeutung nicht und verweist weiterhin auf das ursprüngliche get_data. (Warum? Python bindet den Namen get_data In Ihrer Klasse nur an ein anderes Funktionsobjekt; andere Namensbindungen sind überhaupt nicht betroffen.)

468
Daniel Roseman

Ein MonkeyPatch ist ein Teil von Python) Code, der anderen Code zur Laufzeit erweitert oder modifiziert (normalerweise beim Start).

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.

345
Paolo

Was ist ein Affenpflaster?

Einfach ausgedrückt, ändert Monkey Patching ein Modul oder eine Klasse, während das Programm ausgeführt wird.

Anwendungsbeispiel

Ein Beispiel für das Patchen von Affen finden Sie in der Dokumentation Pandas:

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 zunächst 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 ungebundenen 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

Anschließend 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

Vorsichtsmaßnahme für Namensverfälschung

Wenn Sie die Name-Mangling-Funktion verwenden (das Präfixieren von Attributen mit einem doppelten Unterstrich, der den Namen ändert, und den ich nicht empfehle), müssen Sie die Name-Mangle-Funktion in diesem Fall manuell ausführen. Da ich keine Namensverfälschung empfehle, werde ich dies hier nicht demonstrieren.

Testbeispiel

Wie können wir dieses Wissen zum Beispiel beim Testen nutzen?

Angenommen, wir müssen einen Datenabruf 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 von 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, das darauf beruht, dass diese Methode einen Fehler auslöst, wird dieses Verhalten bei korrekter Implementierung in den Testergebnissen berücksichtigt.

Wenn Sie die obigen Schritte ausführen, wird das Structure -Objekt für die Dauer des Prozesses geändert. Daher sollten Sie Setups und Teardowns in Ihren Unittests verwenden, um dies zu vermeiden. Beispiel:

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

(Während das oben Genannte in Ordnung ist, wäre es wahrscheinlich eine bessere Idee, die Bibliothek mock zu verwenden, um den Code zu patchen. Der Dekorator mock von patch ist weniger fehleranfällig als der Ich habe den Code in mock noch nicht überprüft, aber ich stelle mir vor, er verwendet das Affen-Patchen auf ähnliche Weise.)

110
Aaron Hall

Laut Wikipedia :

In Python bezieht sich der Begriff "Affen-Patch" nur auf dynamische Änderungen einer Klasse oder eines Moduls zur Laufzeit, die darauf zurückzuführen sind, vorhandenen Code von Drittanbietern zu patchen, um einen Fehler oder eine Funktion zu umgehen, der bzw. die nicht Ihren Wünschen entspricht.

28
David Heffernan

Erstens: Affenflicken 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.

17
Andreas Jung

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 das Hinzufügen von Attributen (ob Methoden oder Variablen) zur Laufzeit werden als Affen-Patches bezeichnet, die häufig durchgeführt werden, wenn mit Modulen gearbeitet wird, für die Sie nicht über die Quelle verfügen, sodass die Objektdefinitionen nicht einfach geändert werden können.

Dies wird als schlecht angesehen, da dies bedeutet, dass die Definition eines Objekts nicht vollständig oder genau beschreibt, wie es sich tatsächlich verhält.

13
Aaron Dufour

Monkey-Patching öffnet die vorhandenen Klassen oder Methoden in der Klasse zur Laufzeit erneut und ändert das Verhalten, das mit Vorsicht verwendet werden sollte, oder Sie sollten es nur dann 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.

5
kamal