How to pass self to python decorator?

118 views Asked by At

There is sample code as below:

class Cage(object):
    def __init__(self, func, parent):
        self.func = func
        self.parent = parent

    def __call__(self):
        print('Decorator Cage')
        print(self.parent.age)   # I need to use instance's object of Dog
        print(self.parent.name)
        self.func()

    class Dog(object):
        def __init__(self, age, name):
            self.age = age
            self.name = name

        def dosomedecorate(self):
            print('Do something')

        @Cage
        def dosugar(self):
            print('Do something')

if __name__ == "__main__":

    poppy = Dog(20, 'Louis')

    Cage(poppy.dosomething, poppy)() # It works, but looks weird...

    poppy.dosugar() # Use syntactic sugar will raise error

In this case,

I want to decorate function in class Dog with decorator class Cage.

But, Cage need to use object in Dog

I tried to use syntactic sugar as below:

        @Cage
        def dosugar(self):
            print('Do something')

, then raise error:

TypeError: __init__() missing 1 required positional argument: 'parent'

Is it possible to pass self to decorator?

Or other way to deal with this kind of case?

2

There are 2 answers

0
catalin On

I would do it like that:

def Cage(func):
    def wrapper(self, *args):
        print('Decorator Cage')
        print(self.age)
        print(self.name)
        return func(self, *args)
    
    return wrapper
0
Peter On

Without knowing further details, this at least works for your example while keeping the Cage class (though I prefer the answer by catalin).

class Cage(object):
    def __init__(self, func, parent):
        self.func = func
        self.parent = parent

    def __call__(self):
        print('Decorator Cage')
        print(self.parent.age)
        print(self.parent.name)
        self.func(self.parent)

def cage(func):
    def wrapper(self):
        return Cage(func, self)()
    return wrapper

class Dog(object):
    def __init__(self, age, name):
        self.age = age
        self.name = name

    @cage
    def dosugar(self):
        print('Do something')

Which prints out

Decorator Cage
20
Louis
Do something