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>>
Generics are not just used for function and method parameters. They can also be used to define classes that can contain, or work with, multiple types. These “generic types” allow us to state what type, or types, we want to work with for each instance when we instantiate the class.
Generic functions: from typing import TypeVar, Sequence T = TypeVar('T') # Declare type variable def first(seq: Sequence[T]) -> T: return seq[0] def last(seq: Sequence[T]) -> T: return seq[-1] n = first([1, 2, 3]) # n has type int.
A type constraint on a generic type parameter indicates a requirement that a type must fulfill in order to be accepted as a type argument for that type parameter. (For example, it might have to be a given class type or a subtype of that class type, or it might have to implement a given interface.)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With