动态地用新方法包装任意类



我有一个a级

我有另一个类B。类B的实例应该和类A完全一样,除了一个警告:我想要另一个可用的函数special_method(self, args, kwargs)

因此,以下内容应该有效:

instance_A = classA(args, kwargs)
instance_B = classB(instance_A)
method_result = instance_B.special_method(args, kwargs)

我该如何编写B类来实现这一点?

注意:如果我只想为一个类A做这件事,我可以让类B继承类A。但我希望能够将special_method添加到类C、D、E、F…等等

因此,您正在描述一个代理对象。在Python中,为非特殊方法执行此操作是微不足道的,您可以使用__getattr__

In [1]: class A:
...:     def foo(self):
...:         return "A"
...:
In [2]: class B:
...:     def __init__(self, instance):
...:         self._instance = instance
...:     def special_method(self, *args, **kwargs):
...:         # do something special
...:         return 42
...:     def __getattr__(self, name):
...:         return getattr(self._instance, name)
...:
In [3]: a = A()
In [4]: b = B(a)
In [5]: b.foo()
Out[5]: 'A'
In [6]: b.special_method()
Out[6]: 42

然而,这里有一个警告:这不适用于特殊方法,因为特殊方法跳过了属性解析的这一部分,直接在类__dict__上查找。

或者,您可以简单地将该方法添加到所需的所有类中。类似于:

def special_method(self, *args, **kwargs):
# do something special
return 42
for klass in [A, C, D, E, F]:
klass.special_method = special_method

当然,这会影响这些类的所有实例(因为您只是在向类中动态添加一个方法(。

如果你真的需要特殊的方法,你最好的办法是创建一个子类,但你可以用一个简单的辅助函数动态地做到这一点,例如:

def special_method(self, *args, **kwargs):
# do something special
return 42
_SPECIAL_MEMO = {}
def dynamic_mixin(klass, *init_args, **init_kwargs):
if klass not in _SPECIAL_MEMO:
child = type(f"{klass.__name__}Special", (klass,), {"special_method":special_method})
_SPECIAL_MEMO[klass] = child
return _SPECIAL_MEMO[klass](*init_args, **init_kwargs)
class Foo:
def __init__(self, foo):
self.foo = foo
def __len__(self):
return 88
def bar(self):
return self.foo*2
special_foo = dynamic_mixin(Foo, 10)
print("calling len", len(special_foo))
print("calling bar", special_foo.bar())
print("calling special method", special_foo.special_method())

上面的脚本打印:

calling len 88
calling bar 20
calling special method 42

相关内容

  • 没有找到相关文章

最新更新