如何装饰一个python类和重写一个方法?



我有一个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,可以使用partiallambda)。

首先,为什么不从一开始就定义它,而不是装饰它呢?

第二,为什么不修饰方法本身呢?


你可以重新分配它
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;

最新更新