В pandas
многие методы имеют аргумент ключевого слова inplace
. Это означает, что если inplace=True
, вызываемая функция будет выполнена для самого объекта и вернет None, с другой стороны, если inplace=False
исходный объект останется нетронутым, и метод будет выполнен на возвращенном новом экземпляре. Мне удалось реализовать эту функциональность следующим образом:
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
Работает, как ожидалось. Однако у меня есть много методов, в которых я повторяю тот же шаблон:
def function(self, inplace=True, **kwds)
if inplace:
# do something
else:
obj = copy(self)
obj.function(inplace=True, *args, **kwds)
return obj
Чтобы избежать повторения, я хотел бы создать декоратор и отметить функции, которые могут выполняться на месте, а также не на месте. Я хотел бы использовать его таким образом
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
, и я ожидаю, что он будет вести себя так же, как в приведенном выше примере. Я пробовал писать разные декораторы
(что-то вроде этого
def inplacify(method):
def inner(self, *method_args, **method_kwds):
inplace = method_kwds.pop("inplace", True)
def new_method(inplace, *method_args, **method_kwds):
)
, но каждый раз застревал. Мне нужна ссылка на self
, чтобы вернуть копию класса, которого у меня там нет. Также немного расплывчато изменить сигнатуру функции с помощью декоратора. У меня несколько вопросов: можно ли реализовать такое поведение? Нужен ли мне декоратор класса? Считается ли это плохой практикой, и если да, то что было бы лучшим вариантом для решения такой проблемы?