为 class 中的方法实施就地操作
Implementing inplace operations for methods in a class
在 pandas
中,很多方法都有关键字参数 inplace
。这意味着如果 inplace=True
,被调用的函数将在对象本身上执行,而 returns None,另一方面,如果 inplace=False
原始对象将保持不变,并且该方法在 returned 新实例上执行。我设法实现了如下功能:
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
的参考,以便 return class 的副本,但我那里没有。另外,用装饰器更改函数签名感觉有点模糊。我有几个问题:这种行为可以实现吗?我需要 class 装饰器吗?它是否被认为是一种不好的做法,如果是,处理此类问题的最佳选择是什么?
如果您的方法有 return self
,则以下有效:
import copy
def inplacify(method):
def wrap(self,*a,**k):
inplace = k.pop("inplace",True)
if inplace:
method(self,*a,**k)
else:
return method(copy.copy(self),*a,**k)
return wrap
class classy:
def __init__(self,n):
self.n=n
@inplacify
def func(self,val):
self.n+=val
return self
我测试过:
inst = classy(5)
print(inst.n)
inst.func(4)
print(inst.n)
obj = inst.func(3,inplace=False)
print(inst.n,obj.n)
并得到了预期的结果:
5
9
9 12
希望这能满足您的需求。
在 pandas
中,很多方法都有关键字参数 inplace
。这意味着如果 inplace=True
,被调用的函数将在对象本身上执行,而 returns None,另一方面,如果 inplace=False
原始对象将保持不变,并且该方法在 returned 新实例上执行。我设法实现了如下功能:
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
的参考,以便 return class 的副本,但我那里没有。另外,用装饰器更改函数签名感觉有点模糊。我有几个问题:这种行为可以实现吗?我需要 class 装饰器吗?它是否被认为是一种不好的做法,如果是,处理此类问题的最佳选择是什么?
如果您的方法有 return self
,则以下有效:
import copy
def inplacify(method):
def wrap(self,*a,**k):
inplace = k.pop("inplace",True)
if inplace:
method(self,*a,**k)
else:
return method(copy.copy(self),*a,**k)
return wrap
class classy:
def __init__(self,n):
self.n=n
@inplacify
def func(self,val):
self.n+=val
return self
我测试过:
inst = classy(5)
print(inst.n)
inst.func(4)
print(inst.n)
obj = inst.func(3,inplace=False)
print(inst.n,obj.n)
并得到了预期的结果:
5
9
9 12
希望这能满足您的需求。