Warm tip: This article is reproduced from stackoverflow.com, please click
python

Determine whether function is nested within object

发布于 2020-03-28 23:13:12

I want to write a decorator that can be applied to single functions and to functions that are nested within objects. The difficulty is that I want the decorator to access object variables (via self.var) or function variables (via kwargs).

My sample code to decorate a single function looks like:

def outer_decorator(var_to_print):
    def inner_decorator(function):
        def wrapper(*args, **kwargs):
            if var_to_print in kwargs.keys():
                string_to_print = kwargs.get(var_to_print, "")
                print(string_to_print)
            return function(*args, **kwargs)
        return wrapper
    return inner_decorator

@outer_decorator(var_to_print='var')
def print_something(var=''):
    print('print_second')

print_something(var = 'print_first')
#print_first
#print_second

For objects I want to do something similar but instead of accessing kwargs, I would like to access self.var:

        def wrapper(self, *args, **kwargs):
            string_to_print = getattr(self, var_to_print)
            print(string_to_print)
            return function(self, *args, **kwargs)

Any ideas on how to check dynamically what wrapper should be applied? I tried to check whether it is a callable, but that seems to apply to both.

Questioner
Carsten
Viewed
16
abc 2020-01-31 21:17

You can use isfunction from the inspect module.

Return True if the object is a Python function, which includes functions created by a lambda expression.

>>> from inspect import isfunction
>>> class A():
...     pass
... 
>>> def f():
...     pass
... 
>>> a = A()
>>> isfunction(a)
False
>>> isfunction(f)
True

Actually, what you want to do is to distinguish between functions and methods by using the same decorator for both. A method is still a function. It is considered a method when you access it from the class or from an instance of the class.
There are two options I can think of.

  1. Add an argument to the decorator @outer_decorator(var_to_print='var', f_type='method')
  2. use inspect.getfullargspec under the assumption that in your class you would use self as parameter name and your functions will not. Example:

    if 'self' in inspect.getfullargspec(f)[0]: