通过组合动态实现方法(类似于 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
我正在使用 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