Implementing the decorator pattern in Python

后端 未结 7 1544
梦谈多话
梦谈多话 2020-12-02 09:59

I want to implement the decorator pattern in Python, and I wondered if there is a way to write a decorator that just implements the function it wants to modify, without writ

相关标签:
7条回答
  • 2020-12-02 10:54

    In one of my projects, I also needed to do one particular thing, that is that even the underlying object should actually execute the method that was reimplemented in the decorator. It is actually quite easy to do if you know where to target it.

    The use case is:

    • I have an object X with methods A and B.
    • I create a decorator class Y that overrides A.
    • If I instantiate Y(X) and call A, it will use the decorated A as expected.
    • If B calls A, then if I instantiate Y(X) and call B on the decorator, the call from within B then goes to the old A on the original object which was undesirable. I want the old B to call the new A as well.

    It is possible to reach this behaviour like this:

    import inspect
    import six      # for handling 2-3 compatibility
    
    class MyBaseDecorator(object):
        def __init__(self, decorated):
            self.decorated = decorated
    
        def __getattr__(self, attr):
           value = getattr(self.decorated, attr)
           if inspect.ismethod(value):
               function = six.get_method_function(value)
               value = function.__get__(self, type(self))
           return value
    
    class SomeObject(object):
        def a(self):
            pass
    
        def b(self):
            pass
    
    class MyDecorator(MyBaseDecorator):
        def a(self):
            pass
    
    decorated = MyDecorator(SomeObject())
    

    This may not work out of the box as I typed everything else apart from the getattr method from top of my head.

    The code looks up the requested attribute in the decorated object, and if it is a method (doesn't work for properties now, but the change to support them should not be too difficult), the code then pulls the actual function out of the method and using the descriptor interface invocation it "rebinds" the function as a method, but on the decorator. Then it is returned and most likely executed.

    The effect of this is that if b ever calls a on the original object, then when you have the object decorated and there is any method call coming from the decorator, the decorator makes sure that all methods accessed are bound to the decorator instead, therefore looking up things using the decorator and not the original object, therefore the methods specified in the decorator taking precedence.

    P.S.: Yes I know it looks pretty much like inheritance, but this done in the sense of composition of multiple objects.

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