I have a function which is decorated. When I call __call__.co_names
I want to get the names listed in the function, but instead, it gives me the names listed in the decorator. Let me show you:
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
baz()
return func(*args, **kwargs)
return wrapper
@decorator
def foo():
bar()
def bar():
print('bar is the name I want')
def baz():
print('baz is the name I get')
def foo2(): # undecorated
bar()
foo.__code__.co_names
# ['baz']
foo2.__code__.co_names
# ['bar']
Is there anything I can do to foo
before calling .__code__.co_names
to get the names inside the function rather than the decorator function?
Basically, how do I strip away any decorator functions first?
From the functools
docs:
To allow access to the original function for introspection and other purposes (e.g. bypassing a caching decorator such as
lru_cache()
), this function automatically adds a__wrapped__
attribute to the wrapper that refers to the function being wrapped.
So you can do this:
def get_original_function(f):
return getattr(f, '__wrapped__', f) # default is f, if no __wrapped__ attribute
This also works for functions with multiple decorators; __wrapped__
refers to the original decorated function, so long as each of the decorators uses @wraps
, so there's no need to follow more than one .__wrapped__
reference.