我有一个class
class A:
def sample_method():
我想装饰A类sample_method()
,覆盖sample_method()
的内容
class DecoratedA(A):
def sample_method():
上面的设置类似于继承,但是当使用修饰函数时,我需要保留类A的先前存在的实例。
a # preexisting instance of class A
decorated_a = DecoratedA(a)
decorated_a.functionInClassA() #functions in Class A called as usual with preexisting instance
decorated_a.sample_method() #should call the overwritten sample_method() defined in DecoratedA
正确的做法是什么?
没有一个直接的方法来完成你所要求的。一般来说,在实例创建之后,再去弄乱它的类定义的方法就太晚了。
在我看来,你有两个选择。您可以为已存在的实例创建包装器或代理对象,或者修改实例以更改其行为。
代理将大多数行为延迟到对象本身,而只添加(或覆盖)它自己的一些有限行为:
class Proxy:
def __init__(self, obj):
self.obj = obj
def overridden_method(self): # add your own limited behavior for a few things
do_stuff()
def __getattr__(self, name): # and hand everything else off to the other object
return getattr(self.obj, name)
__getattr__
在这里并不完美,它只能用于常规方法,而不能用于经常在类本身中直接查找的特殊__dunder__
方法。如果你想让你的代理匹配所有可能的行为,你可能需要添加像__add__
和__getitem__
这样的东西,但这在你的特定情况下可能不是必要的(这取决于A
做什么)。
对于更改现有对象的行为,一种方法是编写您的子类,然后将现有对象的类更改为该子类。这有点粗略,因为您从未将对象初始化为新类,但如果您只修改方法行为,它可能会起作用。
class ModifiedA(A):
def overridden_method(self): # do the override in a normal subclass
do_stuff()
def modify_obj(obj): # then change an existing object's type in place!
obj.__class__ = ModifiedA # this is not terribly safe, but it can work
您还可以考虑添加一个实例变量来遮蔽您想要覆盖的方法,而不是修改__class__
。编写函数可能有点棘手,因为它不会在调用时自动绑定到对象(这只发生在作为类属性的函数,而不是实例属性的函数中),但是您可能可以自己执行绑定(如果需要访问self
,可以使用partial
或lambda
)。
首先,为什么不从一开始就定义它,而不是装饰它呢?
第二,为什么不修饰方法本身呢?
你可以重新分配它
class A:
def sample_method(): ...
pass
A.sample_method = DecoratedA.sample_method;
但是这会影响到每一个实例
另一个解决方案是为一个对象重新分配方法。
import functools;
a.sample_method = functools.partial(DecoratedA.sample_method, a);
另一个解决方案是(临时)更改现有对象的类型。
a = A();
a.__class__ = DecoratedA;
a.sample_method();
a.__class__ = A;