I am writing several functions that handle ordered datasets.
Sometime, there is an argument that can be a int
or float
or a timestamp or anything that supports comparison (larger than / smaller than) and that I can use for trimming data for instance.
Is there a way to type-hint such a parameter? The typing module doesn't seem to include this, but is there some other way?
There is no standard 'comparable' ABC, no, as the rich comparison methods are really very flexible and don't necessarily return booleans.
The default built-in types return NotImplemented
when applied to a type they can't be compared with, for example, while specialised libraries like SQLAlchemy and numpy use rich comparison methods to return completely different objects. See the documentation for the rich comparison methods for the details.
But you should be able to define a
a Protocol
subclass for specific expectations:
from typing import Protocol, TypeVar
T = TypeVar("T", infer_variance=True)
class Comparable(Protocol[T]):
def __lt__(self: T, other: T) -> bool:
...
# ... etc
You may need to tweak the protocol to fit your exact expectations, and / or use a non-generic version that's specific to the types you use (perhaps with @overload
ed definitions for specific types).
For sorting with the builtin sorted()
function, just having a __lt__
method should suffice that accepts any value to compare with.
The typeshed project defines a SupportsRichComparison
type alias and SupportsRichComparisonT
typevar bound to the type alias, which is defined as the union of two such protocols:
class SupportsDunderLT(Protocol[_T_contra]):
def __lt__(self, other: _T_contra, /) -> bool: ...
class SupportsDunderGT(Protocol[_T_contra]):
def __gt__(self, other: _T_contra, /) -> bool: ...
SupportsRichComparison: TypeAlias = SupportsDunderLT[Any] | SupportsDunderGT[Any]
SupportsRichComparisonT = TypeVar("SupportsRichComparisonT", bound=SupportsRichComparison)
The built-in sorted()
function is annotated as accepting Iterable[SupportsRichComparisonT]
as its first argument, returning list[SupportsRichComparisonT]
.
You can import these from the _typeshed
package, provided you import them behind a TYPE_CHECKING
guard. This works because type checkers include the typeshed types by default when checking:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from _typeshed import SupportsRichComparisonT