0

Given:

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        #Some code that will execute the decorated method
        func()
    return wrapper


class parent:

    def parentMethod(self):
        pass

class child(parent):

    @my_decorator
    def childMethod(self):
        print("Child method called")


if __name__ == '__main__':
    childInstance = child()

IS there a way to execute the decorated method without calling the decorated method? If that dosen't make any sense, i want basically every method that is decorated with @my_decorator in child class to be executed when a instance of child class is created.

If both above questions are invalid, is there a way to get the methods that are decorated with "@my_decorator" (the names of the methods) without having to call the decorated methods. As a parallel example, the same way you can get the class name that inherits the parent class with self.__class__.__name__

Rolfsky
  • 63
  • 7

2 Answers2

1

You can definitely execute every decorated method on instantiation with some clever meta-programming and reflection. However, this will be complex, difficult to debug, and quite painful to deal with when you (or your colleagues) come back to the code.

You're far better off just calling the methods explicitly in the __init__.


If you really want to go down the route of introspecting the class, try these references:

D Hudson
  • 1,004
  • 5
  • 12
1

It can be done rather easily with the inspect module, by having the decorator add a custom attribute to the method, and using that in __init__:

import inspect

def my_decorator(func):
    print("Something is happening without the function being called.")
    func.deco = True
    return func


class parent:

    def parentMethod(self):
        pass

class child(parent):
    def __init__(self):
        for name, m in inspect.getmembers(self.__class__, inspect.isfunction):
            if hasattr(m, 'deco'):
                m(self)

    @my_decorator
    def childMethod(self):
        print("Child method called")


if __name__ == '__main__':
    childInstance = child()

It gives:

Something is happening without the function being called.
Child method called

The first message is displayed when the child class is defined, the second one when childInstance is initialized.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Indeed it worked, but I really want to change this by moving the execution in the parent class constructor and moving the two classes in two modules also, parentModule.py for parent class and childModule.py for child class. I tried myself but had to change `hasattr(m, 'deco')` bcs it was returning only false with 'deco' in str(m) but it returns an error `TypeError: wrapper() takes 0 positional arguments but 1 was given` any idea if this is possible? – Rolfsky Feb 15 '21 at 10:06
  • @Rolfsky I have just moved the `__init__` method into the `parent` class and it worked exactly the same. – Serge Ballesta Feb 15 '21 at 10:25