In pandas lot's of methods have the keyword argument inplace. This means if inplace=True, the called function will be performed on the object itself, and returns None, on the other hand if inplace=False the original object will be untouched, and the method is performed on the returned new instance. I've managed to implement this functionality as follows:
from copy import copy
class Dummy:
def __init__(self, x: int):
self.x = x
def increment_by(self, increment: int, inplace=True):
if inplace:
self.x += increment
else:
obj = copy(self)
obj.increment_by(increment=increment, inplace=True)
return obj
def __copy__(self):
cls = self.__class__
klass = cls.__new__(cls)
klass.__dict__.update(self.__dict__)
return klass
if __name__ == "__main__":
a = Dummy(1)
a.increment_by(1)
assert a.x == 2
b = a.increment_by(2, inplace=False)
assert a.x == 2
assert b.x == 4
It works as expected. However I have many methods where I repeat that same template:
def function(self, inplace=True, **kwds)
if inplace:
# do something
else:
obj = copy(self)
obj.function(inplace=True, *args, **kwds)
return obj
To avoid repetition, I would like to create a decorator and mark functions which can be executed inplace and also non-inplace. I would like to use it this way
from copy import copy
class Dummy:
def __init__(self, x: int):
self.x = x
@inplacify
def increment_by(self, increment: int):
self.x += increment # just the regular inplace way
def __copy__(self):
cls = self.__class__
klass = cls.__new__(cls)
klass.__dict__.update(self.__dict__)
return klass
and I expect it to behave as the same as the example ahove. I've tried writing different decorators
(something starting like this
def inplacify(method):
def inner(self, *method_args, **method_kwds):
inplace = method_kwds.pop("inplace", True)
def new_method(inplace, *method_args, **method_kwds):
)
but I got stuck every time. I need the reference for self in order to return a copy of the class, which I don't have there. Also it feels a little vague to change the function signature with a decorator. I have several questions: Is this behaviour can be implemented? Do I need a class decorator? Is it considered to be a bad practice, and if so, what would be the best option to deal with such issue?