How can I hint that a type is comparable with typing

前端 未结 2 1922
無奈伤痛
無奈伤痛 2021-01-04 23:31

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

相关标签:
2条回答
  • 2021-01-05 00:03

    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.

    0 讨论(0)
  • 2021-01-05 00:14

    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.

    0 讨论(0)
提交回复
热议问题