通过组合动态实现方法(类似于 kotlin 中的装饰器)

Dynamically implement method by composition (like decorator in kotlin)

我正在使用 Python,并且我有一个接口(一个仅定义方法签名的 class),由另外两个 classes 实现。现在我添加了另一个实现 interface/base-class 的包装器 class,但实际上得到了其他 class 之一,而这个包装器 class 在大多数情况下只是调用其中一个两个 classes。我想做一些 Python 魔法来避免只定义我真正改变的方法。

这是一个例子:

class SomeInterface(object):
    def do_1(self):
        raise Exception("please implement")

    def do_2(self):
        raise Exception("please implement")

    def do_3(self):
        raise Exception("please implement")


class Goo(SomeInterface):
    def do_1(self):
        print("I am goo 1")

    def do_2(self):
        print("I am goo 2")

    def do_3(self):
        print("I am goo 3")

class Foo(SomeInterface):
    def do_1(self):
        print("I am foo 1")

    def do_2(self):
        print("I am foo 2")

    def do_3(self):
        print("I am foo 3")


class WrappingInterface(SomeInterface):
    def __init__(self, inf: SomeInterface):
        self._inner = inf

    def do_1(self):
        self._inner.do_1()

    def do_2(self):
        self._inner.do_2()

    def do_3(self):
        self._inner.do_2()
        print("And then doing something else")

基本上,我不想在包装器 class 中编写 do_1 和 do_2,而是想做一些魔术,并且能够只编写相关代码。

我尝试过使用Mixin实现,但是没有成功。也许装饰器可以做到,但我不确定如何。

我真的不明白你为什么要那样做。您可以从 child class 继承您的 WrappingInterface (例如:从 Foo):

代码:

class WrappingInterface(Foo):

    def do_3(self):
        super().do_3()
        print("And then doing something else")


test = WrappingInterface()
test.do_1()
test.do_2()
test.do_3()

输出:

>>> python3 test.py 
I am foo 1
I am foo 2
I am foo 3
And then doing something else

但是如果你真的需要扩展基础 classes 那么你可以这样做:

动态扩展基础 classes:

class WrappingInterface(SomeInterface):
    def __init__(self, inf: SomeInterface):
        self._inner = inf

    def do_3(self):
        self._inner.do_3()
        print("And then doing something else")


WrappingInterface = type("WrappingInterface", (Foo,), dict(WrappingInterface.__dict__))
test = WrappingInterface(Foo())
test.do_1()
test.do_2()
test.do_3()

输出:

> python3 test.py 
I am foo 1
I am foo 2
I am foo 3
And then doing something else

或者你可以在你的 class 中做所有事情(这有点笨拙,但它有效)。

代码:

class WrappingInterface(SomeInterface):
    def __init__(self, inf: SomeInterface):
        self._inner = inf()
        methods = [method for method in dir(inf) if not method.startswith('__')
                   and callable(getattr(inf, method))]
        for method in methods:
            if method in self.__class__.__dict__:
                continue
            setattr(WrappingInterface, method, getattr(inf, method))

    def do_3(self):
        self._inner.do_3()
        print("And then doing something else")


test = WrappingInterface(Foo)
test.do_1()
test.do_2()
test.do_3()

输出:

>>> python3 test.py 
I am foo 1
I am foo 2
I am foo 3
And then doing something else

注:

我建议检查 Python 中的 Abstract Base Classes 以进行“真正的”抽象。参考:https://docs.python.org/3/library/abc.html