setattr y getattr con métodos

Tengo una clase de plato de caldera que delega algunas acciones a una clase de referencia. Se parece a esto:

class MyClass(): def __init__(self, someClass): self.refClass = someClass def action1(self): self.refClass.action1() def action2(self): self.refClass.action2() def action3(self): self.refClass.action3() 

Esta es la clase de referencia:

 class RefClass(): def __init__(self): self.myClass = MyClass(self) def action1(self): #Stuff to execute action1 def action2(self): #Stuff to execute action2 def action3(self): #Stuff to execute action3 

Me gustaría usar Python Metaprogramming para hacerlo más elegante y legible, pero no estoy seguro de cómo hacerlo.

He oído hablar de setattr y getattr , y creo que podría hacer algo como

 class MyClass(): def __init__(self, someClass): self.refClass = someClass for action in ['action1', 'action2', 'action3']: def _delegate(self): getattr(self.refClass, action)() 

Y luego sé que necesito hacer esto desde algún lugar, supongo:

 MyClass.setattr(action, delegate) 

Simplemente no puedo entender totalmente este concepto. Entiendo lo básico acerca de no repetir código, y generar los métodos con un bucle for con progtwigción funcional, pero luego no sé cómo llamar a estos métodos desde otra parte. Heeeelp!

Python ya incluye soporte para la delegación generalizada a una clase contenida. Solo cambia la definición de MyClass a:

 class MyClass: def __init__(self, someClass): self.refClass = someClass # Note: You call this someClass, but it's actually some object, not some class in your example def __getattr__(self, name): return getattr(self.refClass, name) 

Cuando se define, se llama a __getattr__ en la instancia con el nombre del atributo al que se accede cada vez que no se encuentra un atributo en la instancia en sí. A continuación, delegue en el objeto contenido llamando a getattr para buscar el atributo en el objeto contenido y devolverlo. Esto cuesta un poco cada vez que se realice la búsqueda dinámica, por lo que si quiere evitarlo, puede almacenar __getattr__ atributos de la memoria caché cuando __getattr__ solicita por __getattr__ , por lo que el acceso posterior es directo:

 def __getattr__(self, name): attr = getattr(self.refClass, name) setattr(self, name, attr) return attr 

Personalmente, para delegar cosas normalmente hago algo así:

 def delegate(prop_name, meth_name): def proxy(self, *args, **kwargs): prop = getattr(self, prop_name) meth = getattr(prop, meth_name) return meth(*args, **kwargs) return proxy class MyClass(object): def __init__(self, someClass): self.refClass = someClass action1 = delegate('refClass', 'action1') action2 = delegate('refClass', 'action2') 

Esto creará todos los métodos de delegado que necesitas 🙂

Para algunas explicaciones, la función de delegado aquí simplemente crea una función “proxy” que actuará como un método de clase (¿ve el argumento?) Y pasará todos los argumentos que se le asignen al método del objeto referenciado con los argumentos args y kwargs (vea * args y ** kwargs? para obtener más información sobre estos argumentos)

También puedes crear esto con una lista, pero prefiero la primera porque es más explícita para mí 🙂

 class MyClass(object): delegated_methods = ['action1', 'action2'] def __init__(self, someClass): self.refClass = someClass for meth_name in self.delegated_methods: setattr(self, meth_name, delegate('refClass', meth_name))