Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
476 views
in Technique[技术] by (71.8m points)

mypy: how to verify a type has multiple super classes

I would like mypy to verify that a variable is subclassed from a certain base class and that it also has a specific mixin. Union only verifies that the value is of one type or another. I need to check that the value is both types.

In the example, I'm making up a keyword "All" to demonstrate the behavior I'm looking for:

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' )

In case it's helpful, the reason I need this is I have my own win32 wrapper implemented in Python. My Base class is the basic Window class. My required Mixin is ControlHost which adds specific window styles and functions to the Window class to manage owning children, things that a basic window doesn't need. When creating child controls, like a ComboBox for example, I want mypy to call me out if the parent window I feed it doesn't have both super classes.

Also, I'm having an issue calling Window.init() from Control.init() because of a change of the parent's type. Here's abbreviated pseudo-code that illustrates the problem:

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

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

My work-around looks like this, but it doesn't allow mypy to catch type infractions:

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 ) )
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

What you're basically looking for here are "intersection types".

Unfortunately, mypy (and any other PEP 484-compliant type checkers) do not support intersection types.

There is, however, some discussion about adding such a type -- you can find some discussion on the typing/PEP 484 issue tracker.

Unfortunately, my understanding (after talking to the mypy core devs yesterday) is that while they agree such a type would be useful, it's pretty low on their priority list: adding intersection types would require a substantial amount of careful thought and implementation work. (For example, working out what happens when unions, intersections, and type variables are combined.)

It would probably be helpful if you tried contributing your example/use case to that thread -- if it turns out most people who want intersection types want it for specifically mixins or something, it may be possible for the mypy devs to think of a different way to support that specific use case without implementing full-fledged intersection types.


As an interim measure, you can perhaps use Protocols: define a protocol containing the methods from both the base and mixin classes and use that as the function's type.

(That said, I imagine your window classes have a lot of methods, so this may not be such a feasible solution in your case.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...