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

roy*_*ce3 6 mypy

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

在示例中,我编写了一个关键字“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' )
Run Code Online (Sandbox Code Playgroud)

如果它有帮助的话,我需要这个的原因是我有自己的用 Python 实现的 win32 包装器。我的基类是基本的 Window 类。我需要的 Mixin 是 ControlHost,它向 Window 类添加特定的窗口样式和函数来管理拥有的子窗口,这是基本窗口不需要的东西。创建子控件(例如 ComboBox)时,如果我提供给它的父窗口没有两个超类,我希望 mypy 能够调用我。

另外,我在调用 Window. 从Control.init () 开始。init () 因为父类型的改变。这是说明问题的简短伪代码:

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

class Control ( Window ):
    def __init__ ( self, parent, .... ):
        # type: ( Optional[ControlHost], .... )
Run Code Online (Sandbox Code Playgroud)

我的解决方法如下所示,但它不允许 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 ) )
Run Code Online (Sandbox Code Playgroud)

Mic*_*x2a 6

您在这里基本上寻找的是“交叉点类型”。

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

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

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

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


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

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