Python decorators are fun to use, but I appear to have hit a wall due to the way arguments are passed to decorators. Here I have a decorator defined as part of a base class (the decorator will access class members hence it will require the self parameter).
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 ...
I've omitted the rest of the implementation. Now this class is a base class for various SubSystems that will inherit from it - some of the inherited classes will need to use the UpdateGUI decorator.
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
Once again I have omitted the function implementations as they are not relevant.
In short the problem is that while I can access the decorator defined in the base class from the inherited class by specifiying it as SubSystem.UpdateGUI, I ultimately get this TypeError when trying to use it:
unbound method UpdateGUI() must be called with SubSystem instance as first argument (got function instance instead)
This is because I have no immediately identifiable way of passing the self
parameter to the decorator!
Is there a way to do this? Or have I reached the limits of the current decorator implementation in Python?
In Python, decorators can be either functions or classes. In both cases, decorating adds functionality to existing functions.
A decorator in Python is a function that takes another function as its argument, and returns yet another function . Decorators can be extremely useful as they allow the extension of an existing function, without any modification to the original function source code.
A decorator in Python is any callable Python object that is used to modify a function or a class. A reference to a function "func" or a class "C" is passed to a decorator and the decorator returns a modified function or class.
In fact, there are two types of decorators in Python — class decorators and function decorators — but I will focus on function decorators here.
You need to make UpdateGUI
a @classmethod
, and make your wrapper
aware of self
. A working example:
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
It might be easier to just pull the decorator out of the SubSytem
class: (Note that I'm assuming that the self
that calls setport
is the same self
that you wish to use to call 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')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With