python - 如何让 Mypy 使用多个相互依赖的 mixin?
问题描述
目前在 Electrum 中,我们使用Union
on 类型self
来访问来自多个混合父类的方法。例如,QtPluginBase
依靠混入一个子类HW_PluginBase
来工作。例如,有效的用法是class TrezorPlugin(QtPluginBase, HW_PluginBase)
.
有 Qt gui、Kivy gui,还有 CLI。虽然没有为 Kivy 实现硬件钱包,但它们可能会在未来实现。您已经可以在 CLI 上使用它们。
然而,也有多家硬件钱包制造商,都有自己的插件。
考虑 Trezor + Qt:
对于 Qt,我们有这样的类层次结构:
electrum.plugins.hw_wallet.qt.QtPluginBase
被使用electrum.plugins.trezor.qt.QtPlugin(QtPluginBase)
对于 Trezor,我们有:
electrum.plugin.BasePlugin
被使用electrum.plugins.hw_wallet.plugin.HW_PluginBase(BasePlugin)
被使用electrum.plugins.trezor.trezor.TrezorPlugin(HW_PluginBase)
并创建实际的 Qt Trezor 插件:
electrum.plugins.trezor.qt.Plugin(TrezorPlugin, QtPlugin)
关键是基本的 gui-neutral 插件将首先获得制造商特定的方法;然后它将获得特定于gui的方法。
Aaron(在评论中)建议QtPluginBase
可以子类HW_PluginBase
化,但这意味着制造商特定的东西会出现,这意味着 CLI 或 Kivy 不能使用生成的类。
请注意,两者
electrum.plugins.trezor.trezor.TrezorPlugin(HW_PluginBase)
和
electrum.plugins.hw_wallet.qt.QtPluginBase
依靠HW_PluginBase
。他们不能都继承它。
因此,如果我们避免混入,那么唯一的选择是要么有QtPluginBase
子类TrezorPlugin
(但有很多制造商),要么TrezorPlugin
可以子类QtPluginBase
但同样,生成的类不能被 CLI 或 Kivy 使用。
我意识到这Union
是一个“或”,所以这个提示确实没有意义。但是没有Intersection
类型。使用 Union,大部分 PyCharm 功能都可以工作。
一件很好的事情是,如果QtPluginBase
可以有一个类型提示,它是子类HW_PluginBase
,但实际上在运行时没有子类化。
怎么能用 Mypy 输入,而不必Union
在每个方法上使用这个 hacky 类型提示(因为每个方法都有self
)?
解决方案
使用PEP-544 (Python 3.8+) 中添加的协议,您可以自己定义交集接口!ClassA
这也使您可以隐藏您不想使用的实现细节ClassB
。
from typing import Protocol
class InterfaceAB(Protocol):
def method_a(self) -> None: ...
def method_b(self) -> None: ...
class ClassA:
def method_a(self) -> None:
print("a")
class ClassB:
def method_b(self: InterfaceAB) -> None:
print("b")
self.method_a()
# if I remove ClassA here, I get a type checking error!
class AB(ClassA, ClassB): pass
ab = AB()
ab.method_b()
# % mypy --version
# mypy 0.761
# % mypy mypy-protocol-demo.py
# Success: no issues found in 1 source file
此文件的初始版本归功于 SomberNight/ghost43。
推荐阅读
- ios - 将 Firebase 添加到动态框架中时,没有这样的模块“Firebase”
- flutter - Flutter:具有默认材料压延设计的 DateRangePicker
- mongodb - 在猫鼬中查找条件
- angular - 同一网址页面中的 Ionic 5 路由
- java - java中第n次出现的子字符串
- python - ValueError:不支持未知格式:ROC 曲线
- wpf - 为什么我得到 FreezableCollection`1 在 XAML 设计器中不是有效值
- javascript - 有什么方法可以调用 API 并且之前可以在构造函数中使用响应?
- c# - 尝试使用 services.AddScoped 注入时出错
- asynchronous - 节点 OPCUA 服务器和值的异步设置器