programacion poo otra orientada objetos metodos metodo llamar herencia ejemplo decoradores clases clase python inheritance ironpython decorator

poo - programacion orientada a objetos python pdf



Los decoradores de Python que son parte de una clase base no se pueden usar para decorar funciones de miembros en clases heredadas (4)

Has respondido la pregunta al preguntarla: ¿qué argumento esperarías obtener si llamas a SubSystem.UpdateGUI ? No hay una instancia obvia que deba pasarse al decorador.

Hay varias cosas que podrías hacer para evitar esto. ¿Tal vez ya tienes un subSystem que has subSystem en otra parte? Entonces podrías usar su decorador:

subSystem = SubSystem() subSystem.UpdateGUI(...)

Pero tal vez no necesitabas la instancia en primer lugar, ¿solo la clase SubSystem ? En ese caso, use el decorador classmethod para decirle a Python que esta función debe recibir su clase como primer argumento en lugar de una instancia:

@classmethod def UpdateGUI(cls,...): ...

Finalmente, ¡quizás no necesites acceder a la instancia o a la clase! En ese caso, use staticmethod :

@staticmethod def UpdateGUI(...): ...

Ah, por cierto, la convención de Python es reservar los nombres de CamelCase para las clases y usar los nombres mixedCase o under_scored para los métodos en esa clase.

Los decoradores de Python son divertidos de usar, pero parece que choqué contra una pared debido a la forma en que los argumentos se transmiten a los decoradores. Aquí tengo un decorador definido como parte de una clase base (el decorador tendrá acceso a los miembros de la clase, por lo tanto, requerirá el parámetro automático).

class SubSystem(object): def UpdateGUI(self, fun): #function decorator def wrapper(*args): self.updateGUIField(*args) return fun(*args) return wrapper def updateGUIField(self, name, value): if name in self.gui: if type(self.gui[name]) == System.Windows.Controls.CheckBox: self.gui[name].IsChecked = value #update checkbox on ui elif type(self.gui[name]) == System.Windows.Controls.Slider: self.gui[name].Value = value # update slider on ui ...

He omitido el resto de la implementación. Ahora esta clase es una clase base para varios subsistemas que heredarán de ella; algunas de las clases heredadas necesitarán usar el decorador UpdateGUI.

class DO(SubSystem): def getport(self, port): """Returns the value of Digital Output port "port".""" pass @SubSystem.UpdateGUI def setport(self, port, value): """Sets the value of Digital Output port "port".""" pass

Una vez más, he omitido las implementaciones de funciones ya que no son relevantes.

En resumen, el problema es que, aunque puedo acceder al decorador definido en la clase base de la clase heredada al especificarlo como SubSystem.UpdateGUI, finalmente obtengo este TypeError cuando intento usarlo:

unbound method UpdateGUI() must be called with SubSystem instance as first argument (got function instance instead)

¡Esto se debe a que no tengo una forma inmediatamente identificable de pasar el self parámetro al decorador!

¿Hay alguna forma de hacer esto? ¿O alcancé los límites de la implementación del decorador actual en Python?


Necesita usar una instancia de SubSystem para decorar o usar un classmethod como sugiere Kenny.

subsys = SubSystem() class DO(SubSystem): def getport(self, port): """Returns the value of Digital Output port "port".""" pass @subsys.UpdateGUI def setport(self, port, value): """Sets the value of Digital Output port "port".""" pass

Usted decide qué hacer al decidir si desea que todas las instancias de subclas compartan la misma interfaz GUI o si desea permitir que las distintas tengan interfaces distintas.

Si todos comparten la misma interfaz GUI, utilice un método de clase y haga que todo lo que el decorador acceda a una instancia de clase.

Si pueden tener interfaces distintas, debe decidir si desea representar la distinción con la herencia (en cuyo caso también usaría classmethod y llamará al decorador en las subclases de SubSystem ) o si está mejor representado como instancias distintas. En ese caso, haga una instancia para cada interfaz y llame al decorador en esa instancia.


Necesitas hacer que UpdateGUI un @classmethod , y hacer que tu wrapper consciente de @classmethod self . Un ejemplo de trabajo:

class X(object): @classmethod def foo(cls, fun): def wrapper(self, *args, **kwargs): self.write(*args, **kwargs) return fun(self, *args, **kwargs) return wrapper def write(self, *args, **kwargs): print(args, kwargs) class Y(X): @X.foo def bar(self, x): print("x:", x) Y().bar(3) # prints: # (3,) {} # x: 3


Podría ser más fácil sacar al decorador de la clase SubSytem : (Tenga en cuenta que estoy asumiendo que el self que llama a setport es el mismo self que desea usar para llamar a updateGUIField ).

def UpdateGUI(fun): #function decorator def wrapper(self,*args): self.updateGUIField(*args) return fun(self,*args) return wrapper class SubSystem(object): def updateGUIField(self, name, value): # if name in self.gui: # if type(self.gui[name]) == System.Windows.Controls.CheckBox: # self.gui[name].IsChecked = value #update checkbox on ui # elif type(self.gui[name]) == System.Windows.Controls.Slider: # self.gui[name].Value = value # update slider on ui print(name,value) class DO(SubSystem): @UpdateGUI def setport(self, port, value): """Sets the value of Digital Output port "port".""" pass do=DO() do.setport(''p'',''v'') # (''p'', ''v'')