Reputation: 3048
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.
Upvotes: 1
Views: 285
Reputation: 11929
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.
@outer_decorator(var_to_print='var', f_type='method')
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]:
Upvotes: 3