Search code examples
python-3.xpython-decoratorsinspect

Get co_names of function, not co_names of decorators


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?


Solution

  • 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.