In the Python 3.5 code below, I want to use a less than operator (<
) to compare two generic values. How can I declare a constraint on T to support __lt__
?
from typing import *
import operator
T = TypeVar('T')
class MyList(Generic[T]):
class Node:
def __init__(self, k:T) -> None:
self.key = k
self.next = None # type: Optional[MyList.Node]
def __init__(self) -> None:
self.root = None # type: Optional[MyList.Node]
def this_works(self, val:T) -> bool:
return self.root.key == val
def not_works(self, val:T) -> bool:
return operator.lt(self.root.key, val)
I'm using Mypy to type check and it's failing on not_works
with the message:
$ mypy test.py
test.py: note: In member "not_works" of class "MyList":
test.py:20: error: Unsupported left operand type for < ("T")
Other languages support constraints on T.
In C#: class MyList<T> where T:IComparable<T>
In Java: class MyList<T extends Comparable<? super T>>
You can achieve your goal by passing an extra parameter bound
to TypeVar
, as described in PEP484:
A type variable may specify an upper bound using
bound=<type>
. This means that an actual type substituted (explicitly or implicitly) for the type variable must be a subtype of the boundary type. A common example is the definition of a Comparable type that works well enough to catch the most common errors:
Sample code from mentioned PEP:
from typing import TypeVar
class Comparable(metaclass=ABCMeta):
@abstractmethod
def __lt__(self, other: Any) -> bool: ...
... # __gt__ etc. as well
CT = TypeVar('CT', bound=Comparable)
def min(x: CT, y: CT) -> CT:
if x < y:
return x
else:
return y
min(1, 2) # ok, return type int
min('x', 'y') # ok, return type str
In latest version (verified with 0.521) of mypy, the scenario above is correctly handled.