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

时间:2018-05-13 18:07:04

标签: 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' )

如果它有用,我需要这个的原因是我有自己的用Python实现的win32包装器。 My Base类是基本的Window类。我需要的Mixin是ControlHost,它为Window类添加了特定的窗口样式和函数,以管理拥有的子窗口,基本窗口不需要的东西。在创建子控件时,例如ComboBox,如果我提供的父窗口没有两个超类,我希望mypy给我打电话。

此外,由于父类型的更改,我在Control。 init ()中调用Window。 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 ) )

1 个答案:

答案 0 :(得分:1)

你在这里寻找的是“十字路口类型”。

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

但是,有一些关于添加这种类型的讨论 - 您可以在typing/PEP 484 issue tracker上找到一些讨论。

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

如果您尝试将您的示例/用例提供给该线程可能会有所帮助 - 如果事实证明大多数想要交集类型的人都希望将其用于特定的mixins或其他东西,那么mypy开发人员可能会认为在不实现完整的交集类型的情况下支持该特定用例的不同方式。

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

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