J'essaie de comprendre, qu'est-ce qu'un patch de singe ou un patch de singe?
Est-ce quelque chose comme des méthodes / opérateurs surchargeant ou déléguant?
At-il quelque chose de commun avec ces choses?
J'essaie de comprendre, qu'est-ce qu'un patch de singe ou un patch de singe?
Est-ce quelque chose comme des méthodes / opérateurs surchargeant ou déléguant?
At-il quelque chose de commun avec ces choses?
Réponses:
Non, ce n'est comme aucune de ces choses. Il s'agit simplement du remplacement dynamique d'attributs lors de l'exécution.
Par exemple, considérons 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 - vous remplacez donc dynamiquement la get_data
méthode par un stub qui renvoie des données fixes.
Parce que les classes Python sont mutables et que 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 d'un module exactement de la même manière.
Mais, comme l'a fait remarquer un intervenant, soyez prudent lorsque vous effectuez une opération de monkeyping:
Si quelque chose d'autre que vos appels de logique de test appelle get_data
également, il appellera également votre remplacement patché par un singe plutôt que l'original - ce qui peut être bon ou mauvais. Méfiez-vous.
S'il existe une variable ou un attribut qui pointe également vers la get_data
fonction au moment où vous le remplacez, cet alias ne changera pas sa signification et continuera à pointer vers l'original get_data
. (Pourquoi? Python lie simplement le nom get_data
de votre classe à un autre objet fonction; les autres liaisons de nom ne sont pas du tout affectées.)
pointing to the original get_data function
? Voulez-vous dire que lorsque vous stockez une fonction dans une variable, si quelqu'un change cette fonction, la variable continuera à pointer vers l'ancienne?
get_data
, vous liez à nouveau le nom get_data
à une fonction factice . Si un autre nom quelque part ailleurs dans le programme est lié à la fonction-anciennement connue sous le nom de get_data
, rien ne changera pour cet autre nom.
Un MonkeyPatch est un morceau de code Python qui étend ou modifie un autre code au moment de l'exécution (généralement 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: page MonkeyPatch sur le wiki de Zope.
Qu'est-ce qu'un patch singe?
Autrement dit, le patch de singe apporte des modifications à un module ou à une classe pendant que le programme est en cours d'exécution.
Il y a un exemple de patch de singe dans la documentation 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 une définition de méthode, qui existe non liée et libre en dehors de la portée de toutes les définitions de classe (puisque la distinction est assez dénuée de sens 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 sur laquelle nous voulons l'utiliser:
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
Et puis nous pouvons utiliser la méthode sur une instance de la classe et supprimer la méthode lorsque 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
Si vous utilisez la manipulation de noms (préfixer les attributs avec un double soulignement, ce qui modifie le nom et que je ne recommande pas), vous devrez manuellement modifier les noms si vous faites cela. Comme je ne recommande pas la manipulation de noms, je ne le démontrerai pas ici.
Comment pouvons-nous utiliser ces connaissances, par exemple, dans les tests?
Supposons que nous devons simuler un appel de récupération de données vers une source de données externe qui entraîne une erreur, car nous voulons garantir un comportement correct dans un tel cas. Nous pouvons corriger la structure des données par singe pour garantir ce comportement. (Donc, en utilisant un nom de méthode similaire à celui 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 lorsque nous le testons pour un comportement qui repose sur cette méthode générant une erreur, s'il est correctement implémenté, nous obtiendrons ce comportement dans les résultats du test.
Faire simplement ce qui précède modifiera l' Structure
objet pendant toute la durée du processus, vous voudrez donc utiliser des configurations et des démontages dans vos tests pour éviter de le faire, 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 mock
bibliothèque pour patcher le code. mock
Le patch
décorateur de . Je n'ai pas encore revu le code mock
mais j'imagine qu'il utilise le patch de singe de la même manière.)
Selon Wikipedia :
En Python, le terme correctif de singe fait uniquement référence aux modifications dynamiques d'une classe ou d'un module au moment de l'exécution, motivées par l'intention de corriger le code tiers existant comme solution de contournement à un bogue ou une fonctionnalité qui n'agit pas comme vous le souhaitez.
Premièrement: le patching de singe est un hack diabolique (à 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 consiste à ajouter une solution de contournement pour un bogue dans un module ou une classe lorsque vous ne pouvez pas remplacer le code d'origine. Dans ce cas, vous remplacez le "mauvais" code par le patch de singe par une implémentation à l'intérieur de votre propre module / package.
La correction de singe ne peut être effectuée que dans des langages dynamiques, dont python est un bon exemple. La modification d'une méthode au moment de l'exécution au lieu de mettre à jour la définition d'objet en est un exemple; de même, l'ajout d'attributs (qu'il s'agisse de méthodes ou de variables) au moment de l'exécution est considéré comme une correction de singe. Cela se fait souvent lorsque vous travaillez avec des modules dont vous n'avez pas la source, de sorte que les définitions d'objet ne peuvent pas être facilement modifiées.
Ceci est considéré comme mauvais car cela signifie que la définition d'un objet ne décrit pas complètement ou précisément comment il se comporte réellement.
Le patch de singe rouvre les classes ou méthodes existantes dans la classe au moment de l'exécution et modifie le comportement, qui doit être utilisé avec prudence, ou vous ne devez l'utiliser que lorsque vous en avez vraiment besoin.
Comme Python est un langage de programmation dynamique, les classes sont modifiables afin que vous puissiez les rouvrir et les modifier ou même les remplacer.
Qu'est-ce que le patch de singe? La correction de singe est une technique utilisée pour mettre à jour dynamiquement le comportement d'un morceau de code au moment de l'exécution.
Pourquoi utiliser le patch de singe? Il nous permet de modifier ou d'étendre le comportement des bibliothèques, modules, classes ou méthodes lors de l'exécution sans réellement modifier le code source
Conclusion La correction de singe est une technique intéressante et nous avons maintenant appris à le faire en Python. Cependant, comme nous l'avons vu, il a ses propres inconvénients et doit être utilisé avec précaution.
Pour plus d'informations, veuillez consulter [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.