mypy:如何验证一个类型有多个超类



我希望mypy验证变量是否是从某个基类的子类中子类化的,并且它还具有特定的mixin。联合仅验证值是否属于一种类型或另一种类型。我需要检查该值是否是两种类型。

在示例中,我编造了一个关键字"All"来演示我正在寻找的行为:

from typing import All
class Base ( object ):
pass
class Mixin ( object ):
pass
def assert_all ( x ):
# type: ( All[Base,Mixin] ) -> None
assert isinstance ( x, Base ) and isinstance ( x, Mixin )
class Child ( Mixin, Base ):
pass
assert_all ( Child() )
try:
assert_all ( Base() ) # !!! mypy should complain here
except AssertionError:
pass
else:
raise AssertionError ( 'assert inside of assert_all() should have fired' )
try:
assert_all ( Mixin() ) # !!! mypy should complain here, too
except AssertionError:
pass
else:
raise AssertionError ( 'assert inside of assert_all() should have fired' )

如果它有帮助,我需要它的原因是我用 Python 实现了自己的 win32 包装器。我的基类是基本的窗口类。我所需的 Mixin 是 ControlHost,它将特定的窗口样式和函数添加到 Window 类中,以管理拥有的孩子,这是基本窗口不需要的东西。在创建子控件(例如 ComboBox(时,我希望 mypy 在我馈送它的父窗口没有两个超类时调用我。

另外,我在调用窗口时遇到问题。init(( 来自 Control。init(( 因为父级的类型发生了变化。下面是说明问题的缩写伪代码:

class Window:
def __init__ ( self, parent, .... ):
# type: ( Optional[Window], .... )
class Control ( Window ):
def __init__ ( self, parent, .... ):
# type: ( Optional[ControlHost], .... )

我的解决方法看起来像这样,但它不允许 mypy 捕获类型违规:

class Control ( Control_mixin, Window ):
....
def __init__ ( self, parent=None ):
# type: ( Optional[ControlHost] ) -> None
self.initStyle |= winapi.WS_CHILD|winapi.WS_CLIPSIBLINGS
assert isinstance ( parent, Window )
super ( Control, self ).__init__ ( cast ( Window, parent ) )

你在这里基本上要寻找的是"交叉类型"。

不幸的是,mypy(以及任何其他符合 PEP 484 的类型检查器(不支持交集类型。

但是,有一些关于添加此类类型的讨论 - 您可以在 typing/PEP 484 问题跟踪器上找到一些讨论。

不幸的是,我的理解(在昨天与mypy核心开发人员交谈后(是,虽然他们同意这样的类型是有用的,但它在他们的优先级列表中非常低:添加交叉类型需要大量的仔细思考和实现工作。(例如,计算组合联合、交集和类型变量时会发生什么情况。

如果您尝试将示例/用例贡献给该线程可能会有所帮助 - 如果事实证明大多数想要交叉类型的人都希望它用于特定的混合或其他东西,那么 mypy 开发人员可能会想到一种不同的方法来支持该特定用例而无需实现成熟的交叉类型。


作为临时措施,您也许可以使用协议:定义一个包含基类和 mixin 类的方法的协议,并将其用作函数的类型。

(也就是说,我想你的窗口类有很多方法,所以在你的情况下这可能不是一个可行的解决方案。

最新更新