我有由数据加载器和数据转换器组成的应用程序。每个加载器和每个转换器都是抽象基本加载器和抽象基本转换器的子类,我将在下面的示例中省略它们。具体的加载器和变压器之间存在 1:1 的映射,即知道哪个加载器和变压器属于一起。
假设我们有两个加载器和两个变压器来处理数据
class Data1: ...
class Data2: ...
class Loader1:
def get_data(self) -> Data1: ...
class Loader2:
def get_data(self) -> Data2: ...
class Transformer1:
def transform_data(self, data: Data1) -> None: ...
class Transformer2:
def transform_data(self, data: Data2) -> None: ...
这些类现在可以组合到应用程序中
class App1:
Loader = Loader1
Transformer = Transformer1
class App2:
Loader = Loader2
Transformer = Transformer2
有配套工厂
from typing import Union, Type
def make_app(use_app1: bool) -> Union[Type[App1], Type[App2]]:
if use_app1:
return App1
else:
return App2
这就是我想使用上面的方式
def main(use_app1: bool) -> None:
app = make_app(use_app1)
loader = app.Loader()
data = loader.get_data()
transformer = app.Transformer()
transformer.transform_data(data=data)
但是,mypy complains :
error: Argument "data" to "transform_data" of "Transformer1" has incompatible type "Union[Data1, Data2]"; expected "Data1" [arg-type]
error: Argument "data" to "transform_data" of "Transformer2" has incompatible type "Union[Data1, Data2]"; expected "Data2" [arg-type]
有什么方法可以让mypy
相信分支Loader1 -> Data1 -> Transformer1
和Loader2 -> Data2 -> Transformer2
是分开不会混合?
是否有可用于此用例的替代模式?
最佳答案
好的,这是解决这个问题的第三次尝试。在这次尝试中,我使用抽象协议(protocol)告诉 MyPy,事实上,在许多这些函数中,返回什么特定类型并不重要,只要对象是返回有一定的接口(interface)。
from typing import Type, Protocol, cast
### ABSTRACT INTERFACES ###
class DataProto(Protocol): ...
class LoaderProto(Protocol):
def get_data(self) -> DataProto: ...
class TransformerProto(Protocol):
def transform_data(self, data: DataProto) -> None: ...
class AppProto(Protocol):
Loader: Type[LoaderProto]
Transformer: Type[TransformerProto]
### CONCRETE IMPLEMENTATIONS ###
class Data1: ...
class Data2: ...
class Loader1:
def get_data(self) -> Data1: ...
class Loader2:
def get_data(self) -> Data2: ...
class Transformer1:
def transform_data(self, data: Data1) -> None: ...
class Transformer2:
def transform_data(self, data: Data2) -> None: ...
class App1:
Loader = Loader1
Transformer = Transformer1
class App2:
Loader = Loader2
Transformer = Transformer2
GenericAppClassType = Type[AppProto]
def make_app(use_app1: bool) -> GenericAppClassType:
if use_app1:
return cast(GenericAppClassType, App1)
else:
return cast(GenericAppClassType, App2)
def main(use_app1: bool) -> None:
app = make_app(use_app1)
loader = app.Loader()
data = loader.get_data()
transformer = app.Transformer()
transformer.transform_data(data=data)
在 mypy Playground 上试试 here .
关于python - 将单独的分支组合成公共(public)结构的设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68812899/