Say I want to write a comparison sorting function, I can hint that the input must be a sequence with Sequence[T]
(or MutableSequence[T]
in this cas
As noted in the comments, Comparable
isn't a state of being, it's only meaningful as a descriptor for a pair of types. Usually, a sorting function is working with homogeneous types though, so as long as you don't mind the type checker only handling the concept of "supports <
with some types" rather than "supports <
with arbitrary types", you can define your own Comparable
and bound a typing
TypeVar
with it. Conveniently, PEP484 (which defines typing
hints) already provides an example of how you'd do this:
from abc import ABCMeta
from typing import Any, TypeVar
class Comparable(metaclass=ABCMeta):
@abstractmethod
def __lt__(self, other: Any) -> bool: ...
CT = TypeVar('CT', bound=Comparable)
You can then use this for your comparable_sort
definition with:
def comparable_sort(s: MutableSequence[CT]) -> None:
Note that I only required __lt__
to be defined; as a rule, Python 3 implements its own sorting functions entirely in terms of __lt__
(it doesn't use any of the other rich comparator operators, not even __eq__
)†, so it's a good idea to design your own algorithm the same way, so anything sorted
can handle, you can handle the same way.
†: Python 2 originally used __le__
in at least one place (heapq
), but it's been intentionally, consistently, __lt__
for the builtins and standard library in the Python 3 timeframe, and your style of typing is Python 3-only anyway.
This version works with the current mypy
version.
Based on the thread in the typing
repo: https://github.com/python/typing/issues/59
from __future__ import annotations
from abc import abstractmethod
from typing import MutableSequence, Protocol, TypeVar
class Comparable(Protocol):
"""Protocol for annotating comparable types."""
@abstractmethod
def __lt__(self: CT, other: CT) -> bool:
pass
CT = TypeVar("CT", bound=Comparable)
def comparison_sort(s: MutableSequence[CT]) -> None:
pass
comparison_sort([1, 2, 3]) # OK
comparison_sort([1.0, 2.0, 3.0]) # OK
comparison_sort(["42", "420", "2137"]) # OK
comparison_sort([1, 2, "3"]) # mypy error
link to Github gist.