In this article, we will see how to undecorate a decorated function.
Before hopping into the undecorating part, we need to identify which kind of objects can be decorated by which kind of objects in Python.
Decorators can be implemented in a number of different ways. A decorator, it can be either a class or a function, and wraps a function, a method or a class and alter its running beaviour.
We need to sure that the object we want to undecorate is has a closure. We can use __closure__ magic method to check this.
closure = o.__closure__
After evaluation, if closure
is not null then we can check its closure content.
We will check the cells of the closure and fetch the function that is decorated.
For undecorate operation, there’s already a library but I want to show you how it works simply.
def looks_like_a_decorator(a): return ( isfunction(a) or ismethod(a) or isclass(a) ) def undecorate(o): closure = o.__closure__ if closure: for cell in closure: if cell.cell_contents is o: continue if looks_like_a_decorator(cell.cell_contents): undecd = undecorated(cell.cell_contents) if undecd: return undecd
If you don’t know what cell_contents
is then you can read about closures and try the code after that.
To test, we can simply create a simple class, decorate it and undecorate:
class A(object): decorated = False def decorate(cls): def dec(): ins = cls() ins.decorated = True return ins return dec decorated = decorate(A) assert decorated().decorated is True assert undecorated(decorated) is A assert undecorated(decorated)().decorated is False
and we will get the undecorated object.