Super Monkey Patching en Python: Más allá del Monkey Patching

¿Qué es el Monkey Patching?

El Monkey Patching es como un pequeño truco de magia para cambiar el comportamiento de una función mientras tu código está corriendo. Sí, suena a cosa de hechiceros, pero en realidad es súper útil.

Imagina que tienes una función que consulta una API de precios, como esta:

import requests

def obtener_precios():
    url = "https://store.com/api"
    res = requests.get(url)
    productos = res.json()["productos"]

    for producto, precio in productos.items():
        print(f"El precio de {producto} es {precio}")

Esta función llama a la API y trae precios de productos como televisores y tablets. Pero… Durante las pruebas no quieres hacer esas llamadas externas, ni gastarte todos tus datos. Ahí es donde entra en acción el Monkey Patching.

Ejemplo de Monkey Patching

Vamos a hacerle un “truquillo” a requests.get para que no tenga que llamar a la API real. En lugar de eso, ¡le damos unos datos fakes!

import requests

class SimuladorPrecios:
    def json(self):
        return {
            "productos": {"Televisor": 450, "Tablet": 299}
        }

# Reemplazamos requests.get por nuestra simulación
requests.get = lambda url: SimuladorPrecios()

def obtener_precios():
    url = "https://store.com/api"
    res = requests.get(url)
    productos = res.json()["productos"]

    for producto, precio in productos.items():
        print(f"El precio de {producto} es {precio}")

obtener_precios()
# El precio de Televisor es 450
# El precio de Tablet es 299

Aquí hemos hecho un Monkey Patching guapo para que requests.get no llame a la API real, sino que nos dé una respuesta predefinida con precios de ejemplo.

¿Cuándo usas Monkey Patching?

El Monkey Patching es como un truco de magia: úsalo con moderación y sabiduría. Aquí tienes algunas situaciones en las que puede ser útil:

  • ¿Estás probando funciones que llaman a APIs? Mejor simula la respuesta y evita el drama.
  • ¿Tu función es más lenta que un caracol? Hazle un Monkey Patching y acelera el test.
  • ¿Lo que quieres probar no es la función en sí? Solo cambia el comportamiento que no te interesa.

Super Monkey Patching: Llevando el Monkey Patching al siguiente nivel

Y aquí es donde se pone más interesante… ¡Es hora del Super Monkey Patching!

Imagina que quieres meterte con el código fuente de una función mientras corre y cambiar su comportamiento en vivo. Con la ayuda de inspect.getsource, podemos convertir una función en un string, modificarla, y ejecutarla como si nada. ¡Todo en tiempo real!

import requests

def obtener_precios():
    url = "https://store.com/api"
    res = requests.get(url)
    productos = res.json()["productos"]

    for producto, precio in productos.items():
        print(f"El precio de {producto} es {precio}")

import inspect
print(repr(inspect.getsource(obtener_precios)))

Esto nos devuelve el código de la función como un simple string. Es como leer el guion de una película, pero con más Python.

Super Monkey Patching: Manipulando el código fuente

Ahora, vamos a meter mano y cambiar el código para que, en vez de llamar a la API, devuelva un conjunto de precios fijos. Como quien cambia el guion de una película y le pone su propio toque.

import inspect

def obtener_precios():
    url = "https://store.com/api"
    res = requests.get(url)
    productos = res.json()["productos"]

    for producto, precio in productos.items():
        print(f"El precio de {producto} es {precio}")

# Obtenemos el código fuente de la función
codigo = inspect.getsource(obtener_precios)

# Reemplazamos la llamada a la API por nuestros propios precios
codigo = codigo.replace("res = requests.get", "# res = requests.get")
codigo = codigo.replace("productos = res", "productos = {'Smartphone': 750, 'Tablet': 250} #")

print(codigo)

Aquí hemos dejado de hacer la llamada a la API y, en su lugar, hemos puesto nuestros precios mágicos de un Smartphone a 750 y una Tablet a 250.

Ejecutando el código modificado

Y ahora… ¡a ejecutar el código modificado! Es como si hubiéramos cambiado el final de la película. Pero en vez de palomitas, tenemos Python.

import requests
import inspect

def obtener_precios():
    url = "https://store.com/api"
    res = requests.get(url)
    productos = res.json()["productos"]

    for producto, precio in productos.items():
        print(f"El precio de {producto} es {precio}")

# Obtenemos el código y lo modificamos
codigo = inspect.getsource(obtener_precios)
codigo = codigo.replace("res = requests.get", "# res = requests.get")
codigo = codigo.replace("productos = res", "productos = {'Smartphone': 750, 'Tablet': 250} #")

# Ejecutamos el código con los nuevos precios
exec(codigo)

# Llamamos a la nueva función con nuestros precios
obtener_precios()
# El precio de Smartphone es 750
# El precio de Tablet es 250

Resumen

  1. Extraemos el código fuente con inspect.getsource.
  2. Cambiamos el código a nuestro gusto, como quien cambia las reglas de un juego.
  3. Usamos exec para ejecutar el código modificado y redefinir la función con los nuevos precios.

Este es el poder del Super Monkey Patching: cambias el comportamiento del código mientras sigue corriendo, todo gracias a un pequeño hechizo de funciones y strings.

Conclusión: Por favor, no uses esto en producción. A menos que seas un hechicero, claro. 🧙‍♂️