Python 3.4+inspectfunction
inspect.unwrap()
signatures
Peels off decorator layers: follows the __wrapped__ chain to its last object and returns the original function.
Syntax
inspect.unwrap(func, *, stop=None)
The chain exists only if the decorator uses functools.wraps: without it there is no __wrapped__ and unwrap returns the wrapper as is. The stop parameter halts the descent at the layer you want; the predicate receives every object. A cycle (f.__wrapped__ = f) raises ValueError instead of hanging. signature() and getsource() already unwrap on their own; you need it explicitly to reach the original function, bypassing a cache or a logger.
Examples
import functools, inspect
def cached(fn):
@functools.wraps(fn)
def wrapper(*args):
return fn(*args)
return wrapper
@cached
@cached
def area(w, h):
return w * h
base = inspect.unwrap(area)
print(base is area, base.__name__) # → False area
print(hasattr(base, '__wrapped__')) # → False — это исходная функция
first = inspect.unwrap(area, stop=lambda f: not hasattr(f.__wrapped__, '__wrapped__'))
print(first is area.__wrapped__) # → True — снят один слой
import inspect
def f():
pass
f.__wrapped__ = f
try:
inspect.unwrap(f)
except ValueError as e:
print(type(e).__name__) # → ValueError
See also
Common errors
Open in the full glossarydocs.python.orgReport an inaccuracy