[Python] How to Bound TypeVar Correctly to Protocol?

Discussão em 'Python' iniciado por Stack, Novembro 29, 2024.

  1. Stack

    Stack Membro Participativo

    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...

Compartilhe esta Página