Qu'est-ce que monkey patching?

j'essaie de comprendre, qu'est-ce que le patch de singe ou un patch de singe?

est-ce quelque chose comme les méthodes/opérateurs qui surchargent ou délèguent?

N'ont rien de commun avec ces choses?

378
demandé sur Lutz Prechelt 2011-04-11 23:05:41

7 réponses

non, ce n'est pas comme ça. Il s'agit simplement du remplacement dynamique des attributs à l'exécution.

par exemple, considérez une classe qui a une méthode get_data . Cette méthode effectue une recherche externe (sur une base de données ou une API web, par exemple), et diverses autres méthodes de la classe l'appellent. Cependant, dans un test unitaire, vous ne voulez pas dépendre de la source de données externe - donc vous remplacez dynamiquement la méthode get_data par un talon qui renvoie une partie fixe données.

parce que les classes Python sont mutables, et les méthodes ne sont que des attributs de la classe, vous pouvez le faire autant que vous le souhaitez - et, en fait, vous pouvez même remplacer les classes et les fonctions dans un module de la même manière.

mais, comme un commenter a souligné, utiliser la prudence lorsque l'observation de monkeypatch:

  1. Si autre chose que votre logique de test appelle get_data ainsi, il appellera aussi votre remplacement patché de singe plutôt que l'original -- qui peut être bon ou mauvais. Il suffit de se méfier.

  2. S'il existe une variable ou un attribut qui pointe également vers la fonction get_data au moment où vous le remplacez, ce pseudonyme ne changera pas son sens et continuera de pointer vers l'original get_data . (Pourquoi? Python ne fait que rebinder le nom get_data dans votre classe vers un autre objet de fonction; les autres fixations de nom sont pas touché du tout.)

384
répondu Daniel Roseman 2018-03-20 09:59:37

un MonkeyPatch est un morceau de code Python qui s'étend ou modifie autre code à l'exécution (typiquement au démarrage).

un exemple simple ressemble à ceci:

from SomeOtherProduct.SomeModule import SomeClass

def speak(self):
    return "ook ook eee eee eee!"

SomeClass.speak = speak

Source: MonkeyPatch page sur Zope wiki.

308
répondu Paolo 2014-01-02 09:10:52

Qu'est-ce qu'un patch de singe?

simplement dit, le patch de singe fait des changements à un module ou une classe pendant que le programme est en cours d'exécution.

exemple d'utilisation

il y a un exemple de correction de singe dans la documentation des 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

pour décomposer cela, nous importons d'abord notre module:

import pandas as pd

ensuite nous créons un définition de la méthode, qui existe non liée et libre en dehors de la portée de toute définition de classe (puisque la distinction est assez insignifiante entre une fonction et une méthode non liée, Python 3 supprime la méthode non liée):

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]

ensuite, nous attachons simplement cette méthode à la classe dans laquelle nous voulons l'utiliser:

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class

et ensuite nous pouvons utiliser la méthode sur une instance de la classe, et supprimer la méthode quand nous avons terminé:

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

mise en garde pour le nom du modificateur

si vous utilisez le nom-mangling (préfixer les attributs avec un double-underscore, qui modifie le nom, et que je ne recommande pas) vous aurez à nommer-mangle manuellement si vous faites cela. Puisque je ne recommande pas de nom-mangling, Je ne vais pas le démontrer ici.

Exemple D'Essai

Comment pouvons-nous utiliser ces connaissances, par exemple, dans les tests?

Say nous devons simuler un appel de récupération de données vers une source de données extérieure qui entraîne une erreur, parce que nous voulons assurer un comportement correct dans un tel cas. Nous pouvons patcher la structure de données pour assurer ce comportement. (Donc en utilisant un nom de méthode similaire comme suggéré par Daniel Roseman:)

import datasource

def get_data(self):
    '''monkey patch datasource.Structure with this to simulate error'''
    raise datasource.DataRetrievalError

datasource.Structure.get_data = get_data

et quand nous le testons pour le comportement qui repose sur cette méthode soulevant une erreur, si correctement mis en œuvre, nous obtiendrons ce comportement dans les résultats du test.

le simple fait de faire ce qui précède modifiera l'objet Structure pour la durée du processus, ainsi vous voudrez utiliser les configurations et les teardowns dans vos unitts pour éviter de faire cela, par exemple:

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

(bien que ce qui précède soit correct, ce serait probablement une meilleure idée d'utiliser la bibliothèque mock pour patcher le code. mock 's patch décorateur serait moins susceptible d'erreur que de faire ce qui précède, qui nécessiterait plus de lignes de code et donc plus de les possibilités d'introduire des erreurs. Je n'ai pas encore vérifier le code dans mock mais j'imagine qu'il utilise singe de correction de manière similaire.)

89
répondu Aaron Hall 2017-01-20 17:39:06

selon Wikipedia :

en Python, le terme patch de singe seulement se réfère aux modifications dynamiques d'un classe ou module à l'exécution, motivé par l'intention de corriger existant code de tiers comme solution de contournement à un bogue ou fonctionnalité qui n'agit pas vous désir.

20
répondu David Heffernan 2011-04-11 19:08:52

d'Abord: monkey patching est un mal de hack (à mon avis).

il est souvent utilisé pour remplacer une méthode au niveau du module ou de la classe par une implémentation personnalisée.

le cas d'utilisation le plus courant est l'ajout d'une solution de contournement pour un bogue dans un module ou une classe lorsque vous ne pouvez pas remplacer le code original. Dans ce cas, vous remplacez le "mauvais" code par monkey patching par une implémentation à l'intérieur de votre propre module/paquet.

15
répondu Andreas Jung 2011-04-11 19:11:13

Monkey patching ne peut être fait que dans les langages dynamiques, dont python est un bon exemple. Changer une méthode à l'exécution au lieu de mettre à jour la définition de l'objet en est un exemple;de même, ajouter des attributs (que ce soit des méthodes ou des variables) à l'exécution est considéré comme un patch de singe. Cela se fait souvent lorsque vous travaillez avec des modules pour lesquels vous n'avez pas la source, de sorte que les définitions d'objet ne peuvent pas être changées facilement.

cela est considéré comme mauvais parce que cela signifie que la définition d'un objet ne décrit pas complètement ou avec précision son comportement réel.

9
répondu Aaron Dufour 2011-04-11 20:01:14

Patcher singe est de rouvrir les classes existantes ou les méthodes dans la classe à l'exécution et changer le comportement, qui doit être utilisé avec prudence, ou vous devriez l'utiliser seulement quand vous avez vraiment besoin.

comme Python est un langage de programmation dynamique, les Classes sont mutables pour que vous puissiez les rouvrir et les modifier ou même les remplacer.

3
répondu kamal 2016-01-14 16:48:28