pythonpython-decorators

How to access parent decorator variable in child decorator


I am working on a decorator. To avoid duplicating code I am inheriting a parent decorator which has a nonlocal variable defined. I am not able to get the exact behaviour in my child decorator as I am not able to modify this variable in the parent decorator.

def parentDecorator(func):
    initial=False
    def wrapped(*args,**kwargs):
        nonlocal initial
        if initial:
            print("gettting executed after initial call")
            return func(*args,**kwargs)
        else:
            print("getting executed before initial call")
            initial=True
            res=func(*args,**kwargs)
            return res
    return wrapped

def evaluateCondition():
    return True

def childDecorator(func):
    def wrapped(*args,**kwargs):
        if evaluateCondition():
            myFunc=parentDecorator(func)
            return myFunc(*args,**kwargs)
        else:
            print("do nothing")
    return wrapped

class decoratorTestClass():
    def __init__(self):
        print('init called')
    
    @childDecorator
    def execute(self):
        print("Hello from execute function")

dc=decoratorTestClass()
dc.execute() # this should be called before initialized
dc.execute() # this should be called after initialized

In both the cases the function is getting printed in the else call in the parent decorator. How can I achieve this? I can't change anything in the parent decorator.


Solution

  • The problem with your child decorator is that it is applying your parent decorator multiple times to your method instead of applying it a single time (i.e. you're creating a different closure on each execution of your decorated function). Moving the call to parentDecorator to before the definition of wrapped should fix the issue you're facing:

    def childDecorator(func):
        myFunc = parentDecorator(func) # Move this here
        def wrapped(*args,**kwargs):
            if evaluateCondition():
                return myFunc(*args,**kwargs)
            else:
                print("do nothing")
        return wrapped