¿Qué es el parche de mono?

Resuelto Sergei Basharov asked hace 13 años • 8 respuestas

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

¿Es eso algo así como sobrecargar o delegar métodos/operadores?

¿Tiene algo en común con estas cosas?

Sergei Basharov avatar Apr 12 '11 02:04 Sergei Basharov
Aceptado

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 de la fuente de datos externa, por lo que reemplaza dinámicamente el get_datamétodo 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, puedes hacer esto tanto como quieras y, de hecho, incluso puedes reemplazar clases y funciones en un módulo exactamente de la misma manera.

Pero, como señaló un comentarista , tenga cuidado al aplicar parches a los monos:

  1. Si algo más además de su lógica de prueba get_datatambién llama, también llamará a su reemplazo parcheado en lugar del original, lo cual puede ser bueno o malo. Sólo ten cuidado.

  2. Si existe alguna variable o atributo que también apunta a la get_datafunción cuando la reemplazas, este alias no cambiará su significado y seguirá apuntando al original get_data. (¿Por qué? Python simplemente vuelve a vincular el nombre get_datade su clase a algún otro objeto de función; otras vinculaciones de nombres no se ven afectadas en absoluto).

Daniel Roseman avatar Apr 11 '2011 19:04 Daniel Roseman

Un MonkeyPatch es una pieza de código Python que extiende o modifica otro código en tiempo de ejecución (normalmente 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.

Paolo avatar Jul 11 '2011 08:07 Paolo

¿Qué es un parche de mono?

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

Ejemplo de 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 desglosar esto, primero importamos nuestro módulo:

import pandas as pd

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

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 sobre la manipulación de nombres

Si está utilizando la alteración de nombres (anteponiendo atributos con un guión bajo doble, lo que altera el nombre y lo cual no recomiendo), tendrá que modificar los nombres manualmente si hace esto. Como no recomiendo la manipulación de nombres, no lo demostraré aquí.


Ejemplo de prueba

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

Digamos que necesitamos simular una llamada de recuperación de datos a una fuente de datos externa que resulta en un error, porque queremos garantizar el comportamiento correcto en tal caso. Podemos parchear la estructura de datos para garantizar este comportamiento. (Entonces, usando un nombre de método similar al sugerido por 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 depende de que este método genere un error, si se implementa correctamente, obtendremos ese comportamiento en los resultados de la prueba.

Simplemente hacer lo anterior alterará el Structureobjeto durante la vida del proceso, por lo que querrás usar configuraciones y desmontajes en tus pruebas unitarias para evitar hacerlo, 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 mockbiblioteca para parchear el código. mockEl patchdecorador 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 de introducir errores. . Todavía tengo que revisar el código, mockpero imagino que utiliza el parche de mono de manera similar).

Russia Must Remove Putin avatar Dec 14 '2014 04:12 Russia Must Remove Putin

Según Wikipedia :

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

David Heffernan avatar Apr 11 '2011 19:04 David Heffernan

Primero: el parcheo de monos es un truco malvado (en mi opinión).

A menudo se utiliza para reemplazar un método a nivel de módulo o 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 se puede reemplazar el código original. En este caso, reemplaza el código "incorrecto" mediante parches de mono con una implementación dentro de su propio módulo/paquete.

 avatar Apr 11 '2011 19:04