Python decorators that are part of a base class cannot be used to decorate member functions in inherited classes

前端 未结 4 808
滥情空心
滥情空心 2020-12-28 14:59

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

相关标签:
4条回答
  • 2020-12-28 15:09

    You've sort of answered the question in asking it: what argument would you expect to get as self if you call SubSystem.UpdateGUI? There isn't an obvious instance that should be passed to the decorator.

    There are several things you could do to get around this. Maybe you already have a subSystem that you've instantiated somewhere else? Then you could use its decorator:

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

    But maybe you didn't need the instance in the first place, just the class SubSystem? In that case, use the classmethod decorator to tell Python that this function should receive its class as the first argument instead of an instance:

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

    Finally, maybe you don't need access to either the instance or the class! In that case, use staticmethod:

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

    Oh, by the way, Python convention is to reserve CamelCase names for classes and to use mixedCase or under_scored names for methods on that class.

    0 讨论(0)
  • 2020-12-28 15:19

    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
    
    0 讨论(0)
  • 2020-12-28 15:20

    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')
    
    0 讨论(0)
  • 2020-12-28 15:24

    You need to use an instance of SubSystem to do your decorating or use a classmethod as kenny suggests.

    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
    

    You decide which to do by deciding if you want all subclass instances to share the same GUI interface or if you want to be able to let distinct ones have distinct interfaces.

    If they all share the same GUI interface, use a class method and make everything that the decorator accesses a class instance.

    If they can have distinct interfaces, you need to decide if you want to represent the distinctness with inheritance (in which case you would also use classmethod and call the decorator on the subclasses of SubSystem) or if it is better represented as distinct instances. In that case make one instance for each interface and call the decorator on that instance.

    0 讨论(0)
提交回复
热议问题