There are several ways to identify if a function is wrapped/decorated.
TLDR Solution
def is_decorated(func):
return hasattr(func, '__wrapped__') or func.__name__ not in globals()
Scenario A
If we assume the decorator uses the helper decorator functools.wraps
, then it is pretty straight forward, since our decorated function is going to have the attribute __wrapped__
after.
from functools import wraps
def decorator(function):
@wraps(function)
def _wrapper(*a, **kw): ...
return _wrapper
@decorator
def foo(x, y): ...
def is_decorated(function):
return hasattr(function, '__wrapped__')
Scenario B
In case we don't use wraps
during the decorator's definition, then it's a bit different.
def decorator(function):
def _wrapper(*a, **kw): ...
return _wrapper
@decorator
def foo(x, y): ...
def bar(x, y): ...
print(bar.__name__) # prints 'bar'
print(foo.__name__) # prints '_wrapper' instead of 'foo'
def is_decorated(function):
"""
globals() returns a dictionary which includes
defined functions, classes and many other stuff.
Assuming we haven't defined the inner/wrapper name
as an outer function elsewhere, then it will not be
in globals()
"""
return function.__name__ not in globals()
Conclusion
There are other - more sophisticated - ways to check this, however readability is as important as completeness is, and this solution is as simple it can be. As mentioned in the previous code block, the only "hole" of this solution is the following situation:
from functools import wraps
def is_decorated(func):
return hasattr(func, '__wrapped__') or func.__name__ not in globals()
def decorator_wraps(function):
@wraps(function)
def _wrapper(*a, **kw): ...
return _wrapper
def decorator_no_wraps(function):
def _wrapper(*a, **kw): ...
return _wrapper
@decorator_wraps
def foo(x, y): ...
@decorator_no_wraps
def bar(x, y): ...
def baz(x, y): ...
for function in (foo, bar, baz):
print(is_decorated(function)) # True, True, False
def _wrapper(): ...
for function in (foo, bar, baz):
print(is_decorated(function)) # True, False, False
is_decorated
function that detects if a function has a wrapper function?' – Barbourfunc.__closure__
is not None. A wrapped function is a closure. – Necrose