๐
How to implement custom decorator in python?
Table of contents
What is decorator?
There are two types of decorator function decorator and class decorator the below digrams show how they work.


This is the example of function decorator:
python
import inspectdef auto_repr(cls):print(cls.__name__)members = vars(cls)for name, member in members.items():print(name, member)if "__repr__" in members:raise TypeError(f"{cls.__name__} already defines __repr__")if "__init__" not in members:raise TypeError(f"{cls.__name__} does not override __init__")sig = inspect.signature(cls.__init__) # sig is list of parameter of __init__ functionparameter_names = list(sig.parameters)[1:]if not all(isinstance(members.get(name, None), property)for name in parameter_names):raise TypeError(f"auto_repr does not apply for the {cls.__name__}")def synthesized_repr(self):return "{typename} : {list}".format(typename=self.__class__.__name__,list=", ".join("{name}={value!r}".format(name=name,value=getattr(self, name)) for name in parameter_names))setattr(cls, "__repr__", synthesized_repr)return cls@auto_reprclass SimpleList:def __init__(self, items):self._list = list(items)def add(self, item):self._list.append(item)def sort(self):self._list.sort()@propertydef items(self):return self._list
output
>> from main import *SimpleList__module__ main__init__ <function SimpleList.__init__ at 0x101028c10>add <function SimpleList.add at 0x101028ca0>sort <function SimpleList.sort at 0x101028d30>items <property object at 0x100dfdd00>__dict__ <attribute '__dict__' of 'SimpleList' objects>__weakref__ <attribute '__weakref__' of 'SimpleList' objects>__doc__ None>> s = SimpleList([1,2])>> sSimpleList : items=[1, 2]
Another example for function decorator:
This is example for class decorator factories
python
def post_condition(predicate):def function_decorator(f):@functools.wraps(f)def wrapper(self, *args, **kwargs):result = f(self, *args, **kwargs)if not predicate(self):raise RuntimeError(f"Post-condition {predicate.__name__} not "f"maintained for {self!r}")return resultreturn wrapperreturn function_decoratordef min_length(simple_list):return len(simple_list.items) >= 2class SimpleList:@post_condition(min_length)def __init__(self, items):self._list = list(items)@post_condition(min_length)def add(self, item):self._list.append(item)def sort(self):self._list.sort()@propertydef items(self):return self._lists1 = SimpleList([])s2 = SimpleList([1,2])print(s2)
Output
RuntimeError: Post-condition min_length not maintained for SimpleList : items=[]SimpleList : items=[1, 2]
In this approach we should define decorators above each methods but there is another way, that we define a decorator above class and it is applied for every methods in that class.
python
def post_condition(predicate):def function_decorator(f):@functools.wraps(f)def wrapper(self, *args, **kwargs):result = f(self, *args, **kwargs)if not predicate(self):raise RuntimeError(f"Post-condition {predicate.__name__} not "f"maintained for {self!r}")return resultreturn wrapperreturn function_decoratordef invariant(predicate):function_decorator = post_condition(predicate)def class_decorator(cls):members = list(vars(cls).items())for name, member in members:if inspect.isfunction(member):decorated_member = function_decorator(member)setattr(cls, name, decorated_member)return clsreturn class_decoratordef min_length(simple_list):return len(simple_list.items) >= 2@invariant(min_length)class SimpleList:def __init__(self, items):self._list = list(items)def add(self, item):self._list.append(item)def sort(self):self._list.sort()@propertydef items(self):return self._list
Example for class decorator
For more detail for class decorator check this link