Uso dinámico de métodos con getattr en Python

La expresión result = getattr(self.tools, action)(**args) permite invocar métodos de forma dinámica según el valor de una variable de tipo cadena. A continuación se desglosa su funcionamiento:

1. getattr(self.tools, action)

La función integrada getattr recupera un atributo (o método) de un objeto usando su nombre como cadena.

  • self.tools es una instancia de la clace Tools, que contiene los métodos search y calculate.
  • action es una cadena como "search" o "calculate".
  • Así, getattr(self.tools, action) devuelve una referencia al método correspondiente: self.tools.search o self.tools.calculate.

2. (**args)

El operador ** desempaqueta un diccionario para pasarlo como argumentos nombrados a una función.

  • Si args = {"query": "clima"}, entonces (**args) equivale a query="clima".
  • Si args = {"expr": "3*4"}, entonces (**args) equivale a expr="3*4".

3. Combincaión completa

Supongamos que action = "search" y args = {"query": "clima"}:

result = getattr(self.tools, action)(**args)
# Equivale a:
result = self.tools.search(query="clima")

Y si action = "calculate" con args = {"expr": "3*4"}:

result = getattr(self.tools, action)(**args)
# Equivale a:
result = self.tools.calculate(expr="3*4")

Este patrón permite que un agente decida en tiempo de ejecución qué herramienta usar y con qué parámetros, basándose en el análisis del texto de entrada del usuario.

# agent.py
class Memory:
    def __init__(self):
        self.log = []

    def store(self, entry):
        self.log.append(entry)

class Utilities:
    def lookup(self, term):
        return f"🔍 Resultado: '{term}' — datos de ejemplo"

    def evaluate(self, formula):
        try:
            return f"🧮 Resultado: {eval(formula)}"
        except Exception:
            return "❌ Expresión no válida"

class Assistant:
    def __init__(self):
        self.history = Memory()
        self.utils = Utilities()

    def decide(self, text):
        if "clima" in text or "buscar" in text:
            return "lookup", {"term": text}
        elif any(op in text for op in "+-*/"):
            return "evaluate", {"formula": text}
        return None, {}

    def respond(self, user_text):
        self.history.store(f"Entrada: {user_text}")
        method_name, params = self.decide(user_text)
        if method_name:
            output = getattr(self.utils, method_name)(**params)
            self.history.store(f"Respuesta: {output}")
            return output
        return "🤔 No tengo una acción definida"

if __name__ == "__main__":
    bot = Assistant()
    while True:
        prompt = input("Tú: ")
        print("Asistente:", bot.respond(prompt))

Etiquetas: Python getattr dynamic-method-call

Publicado el 9-5 03:39