In brief, I have a DataFormatter class that has two possible states: train
or infer
, that should act similarly to many of the sklearn libraries that have fit
and transform
functions: if mode is train
I want to store in self.metadata
a list of the function calls and args that were made, so that they can simply be reapplied verbatim and in order at infer
time.
So minimally, I have:
import inspect
class DataFormatter:
def __init__(self, mode, data=None):
self.data = data
self.metadata = []
# The decorator function: broken, but something like--
def meta(self, f, *args):
def wrapper(*args):
return f(*args)
if self.mode == 'train':
print('caching metadata')
meta = {
f.__name__: {
param: arg for param, arg in zip(
inspect.getfillargspec(f).args, args)}}
self.metadata.append(meta)
return wrapper
@meta
def drop(self, cols):
self.data = self.data.drop(cols)
Then if I use:
formatter = DataFormatter('train', my_data)
formatter.drop(['col1', 'col5'])
print(formatter.metadata)
...I would like to get:
[{'drop': {'cols': ['col1', 'col5']}}]
I have tried various permutations and placements of self
, and pulling the decorator func outside the class altogether, but no luck so far.
@kindall says "You can't get self at decoration time because the decorator is applied at function definition time. No self exists yet; in fact, the class doesn't exist yet." (Possible to create a @synchronized decorator that's aware of a method's object?), so not even sure if this is possible...
CodePudding user response:
What will "see" a self is the decorated function - and it is represented by the function you call "wrapper":
import inspect
# The decorator function: should be out of the class body
def meta( f): ,
def wrapper(self, *args):
# call the decorated function:
# (but you could run other code, including inspecting
# and modifying arguments, here as well)
result = f(self, *args)
# now, your original method had run, and you have
# access to self:
if self.mode == 'train':
print('caching metadata')
meta = {
f.__name__: {
param: arg for param, arg in zip(
inspect.getfillargspec(f).args, args)}}
self.metadata.append(meta)
return result
return wrapper
class DataFormatter:
def __init__(self, mode, data=None):
self.data = data
self.metadata = []
@meta
def drop(self, cols):
self.data = self.data.drop(cols)
That will work.