Estoy tratando de entender, ¿qué es un parche de mono o un parche de mono?
¿Es algo así como métodos / operadores que sobrecargan o delegan?
¿Tiene algo en común con estas cosas?
Estoy tratando de entender, ¿qué es un parche de mono o un parche de mono?
¿Es algo así como métodos / operadores que sobrecargan o delegan?
¿Tiene algo en común con estas cosas?
Respuestas:
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 en 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_data
mé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 lo señaló un comentarista , tenga cuidado al parchear mono:
Si hay algo más además de las llamadas de lógica de prueba get_data
, también llamará a su reemplazo parcheado en lugar del original, lo que puede ser bueno o malo. Solo ten cuidado.
Si existe alguna variable o atributo que también apunta a la get_data
función en el momento en que la reemplaza, este alias no cambiará su significado y continuará apuntando al original get_data
. (¿Por qué? Python simplemente vuelve a unir el nombre get_data
de su clase a algún otro objeto de función; otros enlaces de nombre no se ven afectados en absoluto).
pointing to the original get_data function
? ¿Quiere decir que cuando almacena una función dentro de una variable si alguien cambia esa función, la variable continuará apuntando a la anterior?
get_data
, vuelves a vincular el nombre get_data
a una función simulada. Si algún otro nombre en algún otro lugar del programa está vinculado a la función-anteriormente-conocida-como- get_data
, nada cambiará para ese otro nombre.
Un MonkeyPatch es un fragmento de código de Python que extiende o modifica otro código 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 el wiki de Zope.
¿Qué es un parche de mono?
En pocas palabras, el parche de mono está haciendo cambios en un módulo o clase mientras se ejecuta el programa.
Hay un ejemplo de parches de mono 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 sin consolidar y libre fuera del alcance de cualquier definición de clase (dado que la distinción es bastante insignificante entre una función y un método independiente, 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
Si está usando el cambio de nombre (prefijar los atributos con un doble guión bajo, que altera el nombre y que no recomiendo), tendrá que cambiar el nombre manualmente si hace esto. Como no recomiendo el cambio de nombre, no lo demostraré aquí.
¿Cómo podemos usar este conocimiento, por ejemplo, en las pruebas?
Supongamos que necesitamos simular una llamada de recuperación de datos a una fuente de datos externa que resulte en un error, porque queremos asegurar un comportamiento correcto en tal caso. Podemos mono 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 lo probamos para detectar un comportamiento que se basa en que este método genera un error, si se implementa correctamente, obtendremos ese comportamiento en los resultados de la prueba.
Simplemente hacer lo anterior alterará el Structure
objeto durante la vida útil del proceso, por lo que querrá usar configuraciones y desmontajes en sus pruebas de unidad 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 mock
biblioteca para parchear el código. mock
El patch
decorador 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, mock
pero imagino que usa parches de mono de manera similar).
De acuerdo con 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 de terceros existente como una solución a un error o característica que no actúa como usted desea.
Primero: el parcheado de monos es un hack malvado (en mi opinión).
A menudo se usa para reemplazar un método en el 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 puede reemplazar el código original. En este caso, reemplaza el código "incorrecto" a través de parches de mono con una implementación dentro de su propio módulo / paquete.
Los parches de mono solo se pueden 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 parche de mono. A menudo se realizan cuando se trabaja con módulos para los que no tiene la fuente, de modo que las definiciones de 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.
Monkey parchear es reabrir las clases o métodos existentes en clase en tiempo de ejecución y cambiar el comportamiento, que debe usarse con precaución, o debe usarlo solo cuando realmente lo necesite.
Como Python es un lenguaje de programación dinámico, las clases son mutables para que pueda volver a abrirlas y modificarlas o incluso reemplazarlas.
¿Qué es el parcheado de monos? Los parches de mono son una técnica utilizada para actualizar dinámicamente el comportamiento de un fragmento de código en tiempo de ejecución.
¿Por qué usar parches de mono? Nos permite modificar o ampliar el comportamiento de bibliotecas, módulos, clases o métodos en tiempo de ejecución sin modificar realmente el código fuente
Conclusión Los parches de mono son una técnica genial y ahora hemos aprendido cómo hacerlo en Python. Sin embargo, como discutimos, tiene sus propios inconvenientes y debe usarse con cuidado.
Para obtener más información, consulte [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.