Combining several structural types in python

Viewed 317

How do I specify an object that must satisfy several protocols? For instance, suppose I need an object that satisfies both Reversible and Iterable:

from typing import Iterable, Reversible

l = [1, 2, 3]
r: Reversible[int] = l
i: Iterable[int] = l
reversed(r)  # fine
iter(i)  # fine
reversed(i)  # err since not iterable
iter(r)  #err since not reversible

I would like to somehow annotate a variable where all operations are possible. For instance (made up syntax):

T = TypeVar('T')
ReversibleIterable = Intersection[Reversible[T], Iterable[T]]

ri: ReversibleIterable[int] = l
reversed(ri)  # fine
iter(ri)  # fine

Does such a thing exist? I searched for work arounds using protocols, bounded TypeVars, etc. but was unable to make it work.

1 Answers

ReversibleIterable = Intersection[Reversible[T], Iterable[T]]

There is an old open proposal regarding intersection types: typing#213. No approval of it so far.

I searched for work arounds using protocols

You can indeed introduce your own intersection protocol:

_T_co = TypeVar("_T_co", covariant=True)


class ReversibleIt(Reversible[_T_co], Iterable[_T_co], Protocol[_T_co]):
    pass


r: ReversibleIt[int] = [1, 2, 3]
Related