I want to type annotate a simple sorting function that receives a list of any values that have either __lt__, __gt__, or both, but not mixed methods (i.e., all values should have the same comparison method) and returns a list containing the same elements it received in sorted order. What I've done so far: from typing import Any, Protocol class SupportsLT(Protocol): def __lt__(self, other: Any, /) -> bool: ... class SupportsGT(Protocol): def __gt__(self, other: Any, /) -> bool: ... def quick_sort[T: SupportsLT | SupportsGT](seq: list[T]) -> list[T]: if len(seq) <= 1: return list(seq) pivot = seq[0] smaller: list[T] = [] larger_or_equal: list[T] = [] for i in range(1, len(seq)): item = seq if item < pivot: smaller.append(item) else: larger_or_equal.append(item) return [*quick_sort(smaller), pivot, *quick_sort(larger_or_equal)] Running mypy --strict gives the error: error: Unsupported left operand type for < (some union) [operator]. I think this is because there is no guarantee that the values do not have mixed protocols. Another attempt is using constraints instead of bound: def quick_sort[T: (SupportsLT, SupportsGT)](seq: list[T]) -> list[T]: if len(seq) <= 1: return list(seq) pivot = seq[0] smaller: list[T] = [] larger_or_equal: list[T] = [] for i in range(1, len(seq)): item = seq if item < pivot: smaller.append(item) else: larger_or_equal.append(item) return [*quick_sort(smaller), pivot, *quick_sort(larger_or_equal)] When I run mypy --strict, I get complaints about the type of the list returned by the return statement: error: List item 0 has incompatible type "list[T]"; expected "SupportsLT" [list-item] error: List item 0 has incompatible type "list[T]"; expected "SupportsGT" [list-item] error: List item 2 has incompatible type "list[T]"; expected "SupportsLT" [list-item] error: List item 2 has incompatible type "list[T]"; expected "SupportsGT" [list-item] However, the second attempt has a significant issue. Running the following gives Revealed type is "builtins.list[SupportsLT]", which should be "builtins.list[builtins.int]" instead: from typing import reveal_type x = quick_sort([12, 3]) reveal_type(x) python version: 3.13.0, mypy version: 1.13.0 UPDATE: The reason I'm using both SupportsLT and SupportsGT as bound while my function only utilizes the less-than operator (i.e., <) is that when the left-hand operand lacks the __lt__ method, Python calls the __gt__ method of the right-hand operand and passes the left operand as an argument. Thus, values with only __gt__ should be considered valid as input to my function. Consider the following simple example: from typing import Self class HasGT: def __init__(self, value: int) -> None: self.value = value def __gt__(self, other: Self) -> bool: return self.value > other.value print(HasGT(5) < HasGT(6)) # Prints True Continue reading...