python terminology monkeypatching

python - ¿Qué es el parche de mono?



terminology monkeypatching (7)

¿Qué es un parche de mono?

En pocas palabras, el parche de mono está realizando cambios en un módulo o clase mientras el programa se está ejecutando.

Ejemplo en uso

Hay un ejemplo de parcheo de monos en la documentación de 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

Para descomponerlo, primero importamos nuestro módulo:

import pandas as pd

A continuación, creamos una definición de método, que existe sin límites y libre fuera del alcance de cualquier definición de clase (ya que la distinción no tiene mucho sentido entre una función y un método no vinculado, Python 3 elimina el método no vinculado):

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]

A continuación, simplemente adjuntamos ese método a la clase en la que queremos usarlo:

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

Y luego podemos usar el método en una instancia de la clase y eliminar el método cuando hayamos terminado:

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

Advertencia para el nombre de mangling

Si está usando la manipulación de nombres (prefijando atributos con un doble guión bajo, lo que altera el nombre, y no lo recomiendo), deberá hacerlo manualmente si hace esto. Como no recomiendo el uso de nombres, no lo demostraré aquí.

Ejemplo de prueba

¿Cómo podemos usar este conocimiento, por ejemplo, en las pruebas?

Supongamos que necesitamos simular una llamada de recuperación de datos a un origen de datos externo que resulte en un error, porque queremos garantizar el comportamiento correcto en ese caso. Podemos modificar la estructura de datos para asegurar este comportamiento. (Entonces, usando un nombre de método similar como lo sugiere 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

Y cuando probamos el comportamiento que se basa en que este método genere un error, si se implementa correctamente, obtendremos ese comportamiento en los resultados de la prueba.

El solo hecho de hacer lo anterior alterará el objeto de Structure durante la vida del proceso, por lo que querrá usar configuraciones y desmontes en sus pruebas de unidad para evitar hacer eso, por ejemplo:

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

(Si bien lo anterior está bien, probablemente sería una mejor idea usar la biblioteca mock para parchear el código. El decorador de patch mock sería menos propenso a errores que hacer lo anterior, lo que requeriría más líneas de código y, por lo tanto, más oportunidades) para introducir errores. Todavía tengo que revisar el código en mock pero me imagino que utiliza parches de mono de una manera similar.)

Estoy tratando de entender, ¿qué es el parche de mono o un parche de mono?

¿Es algo así como métodos / operadores sobrecargando o delegando?

¿Tiene algo en común con estas cosas?


Un MonkeyPatch es un fragmento de código Python que extiende o modifica otros códigos en tiempo de ejecución (generalmente al inicio).

Un ejemplo simple se ve así:

from SomeOtherProduct.SomeModule import SomeClass def speak(self): return "ook ook eee eee eee!" SomeClass.speak = speak

Fuente: página de MonkeyPatch en la wiki de Zope.


El parche de mono es volver a abrir las clases o métodos existentes en clase en tiempo de ejecución y cambiar el comportamiento, que debe usarse con precaución, o solo debe usarlo cuando realmente lo necesite.

Como Python es un lenguaje de programación dinámico, las clases son mutables, por lo que puede volver a abrirlas y modificarlas o incluso reemplazarlas.


El parcheo de monos solo se puede hacer en lenguajes dinámicos, de los cuales Python es un buen ejemplo. Cambiar un método en tiempo de ejecución en lugar de actualizar la definición del objeto es un ejemplo, de manera similar, agregar atributos (ya sean métodos o variables) en tiempo de ejecución se considera parcheo de monos. A menudo, se realizan cuando se trabaja con módulos para los que no tiene la fuente, de modo que las definiciones de los objetos no se pueden cambiar fácilmente.

Esto se considera malo porque significa que la definición de un objeto no describe completa o exactamente cómo se comporta realmente.


No, no es como ninguna de esas cosas. Es simplemente el reemplazo dinámico de atributos en tiempo de ejecución.

Por ejemplo, considere una clase que tiene un método get_data . Este método realiza una búsqueda externa (en una base de datos o API web, por ejemplo), y varios otros métodos de la clase lo llaman. Sin embargo, en una prueba unitaria, no desea depender del origen de datos externo, por lo que reemplaza dinámicamente el método get_data con un código auxiliar que devuelve algunos datos fijos.

Debido a que las clases de Python son mutables, y los métodos son solo atributos de la clase, puede hacer todo lo que quiera y, de hecho, incluso puede reemplazar clases y funciones en un módulo exactamente de la misma manera.

Pero, como lo un , tenga cuidado al hacer el "monkeypatching":

  1. Si cualquier otra cosa además de la lógica de prueba también llama a get_data , también llamará a su reemplazo con parches de mono en lugar del original, lo que puede ser bueno o malo. Sólo ten cuidado.

  2. Si existe alguna variable o atributo que también apunta a la función get_data en el momento en que la reemplace, este alias no cambiará su significado y continuará apuntando a la get_data original. (¿Por qué? Python simplemente vuelve a unir el nombre get_data en su clase a algún otro objeto de función; otros enlaces de nombres no se ven afectados en absoluto).


Primero: parchar a los monos es un truco malvado (en mi opinión).

A menudo se usa para reemplazar un método en el módulo o nivel de clase con una implementación personalizada.

El caso de uso más común es agregar una solución alternativa para un error en un módulo o clase cuando no puede reemplazar el código original. En este caso, reemplaza el código "incorrecto" a través de la aplicación de parches mono con una implementación dentro de su propio módulo / paquete.


Según Wikipedia :

En Python, el término parche de mono solo se refiere a modificaciones dinámicas de una clase o módulo en tiempo de ejecución, motivado por la intención de parchear el código existente de terceros como una solución a un error o característica que no funciona como usted desea.