Farhood ET
Farhood ET

Reputation: 1541

How to typehint that an object of a class is also adhering to a Protocol in Python?

I have a set of classes, Lets call them Foo and Bar, where both inherit from a base class Father that is defined outside of the current scope (not by me). I have defined a protocol class DummyProtocol that has a function do_something.

class DummyProtocol(Protocol):
   def do_something(self):
      ...
   

class Foo(Father):
   def do_something(self):
      pass

class Bar(Father):
   def do_something(self):
      pass

I have a function create_instance.

def create_dummy_and_father_instance(cls, *args, **kwargs):
    return cls(*args, **kwargs)

I want to typehint it in a way, that cls is typehinted to accept a class that is of type Father that also implements the DummyProtocol.

So I changed the function to this to indicate that cls is a type that inherit from both Father and DummyProtocol

def create_dummy_and_father_instance(
    cls: Type[tuple[Father, DummyProtocol]], *args, **kwargs
):
    return cls(*args, **kwargs)

But I get this error in mypy:

Cannot instantiate type "Type[Tuple[Father, DummyProtocol]]"

Upvotes: 8

Views: 2726

Answers (2)

tepsijash
tepsijash

Reputation: 400

I came across the same issue and found this discussion on proposed Intersection types which seem to be exactly what is needed (e.g. see this comment).

Unfortunately this feature is not yet supported by the Python typing system, but there's a PEP in the making.

Upvotes: 5

hussic
hussic

Reputation: 1920

You can define a second Father class which inherits from Father and Protocol (see also mypy: how to verify a type has multiple super classes):

class DummyProtocol(Protocol):

    def do_something(self):
        ...
    
class Father:
    pass
    
class Father2(Father, DummyProtocol):
    pass
    
class Foo(Father2):

    def do_something(self):
        pass
    
class Bar(Father2):

    def do_something(self):
        pass
    
class FooNot(Father):
    pass
    
def create_dummy_and_father_instance(
    cls: Type[Father2]
):
    return cls()
    
create_dummy_and_father_instance(Foo)
create_dummy_and_father_instance(Bar)
create_dummy_and_father_instance(FooNot)  # mypy error ok

Upvotes: 2

Related Questions