mypy 泛型可以表达将 return 序列类型作为参数传递吗?
Can mypy generics express passing the return sequence type as an argument?
我想编写以下通用 Python 代码:
from itertools import chain
from typing import Sequence, Hashable, List, Tuple, Type, TypeVar
SequenceT = TypeVar('SequenceT', bound=Sequence)
HashableT = TypeVar('HashableT', bound=Hashable)
def merge_and_sort_into(seq_type, *iterables):
# type: (Type[SequenceT], *Iterable[HashableT]) -> SequenceT[HashableT]
return seq_type(sorted(set(chain(*iterables))))
def merge_and_sort_into_list(*iterables):
# type: (*Iterable[HashableT]) -> List[HashableT]
return merge_and_sort_into(list, *iterables)
def merge_and_sort_into_tuple(*iterables):
# type: (*Iterable[HashableT]) -> Tuple[HashableT]
return merge_and_sort_into(tuple, *iterables)
代码很好,但是 mypy 不喜欢 merge_and_sort_into()
的 return 类型说 error: Type variable "SequenceT" used with arguments
。如何将 Sequence 类型传递给函数并将该类型用作 return 类型? (注意:我没有捕捉到序列的值类型也需要是 comparable/sortable 的事实,但让我们忽略它)。
这是 mypy 将接受的版本,但它没有捕获传递给 merge_and_sort_into()
的类型是它的 return 类型的约束,因此是强制转换。
def merge_and_sort_into(seq_type, *iterables):
# type: (Callable[[Iterable[HashableT]], Sequence[HashableT]], *Iterable[HashableT]) -> Sequence[HashableT]
return seq_type(sorted(set(chain(*iterables))))
def merge_and_sort_into_list(*iterables):
# type: (*Iterable[HashableT]) -> List[HashableT]
return cast(List[HashableT], merge_and_sort_into(list, *iterables))
def merge_and_sort_into_tuple(*iterables):
# type: (*Iterable[HashableT]) -> Tuple[HashableT]
return cast(Tuple[HashableT], merge_and_sort_into(tuple, *iterables))
Mypy 不支持泛型类型变量,因为它们需要类型系统支持更高种类,如 this comment 中所述。
即使 Mypy 支持泛型类型变量,原始函数的类型签名也会不正确,因为并非所有 Sequence
都可以从可迭代对象构造。例如,
class EmptyList(Sequence[T]):
def __init__(self): pass
def __getitem__(self, item): raise IndexError
def __len__(self): return 0
EmptyList([1, 2, 3]) # TypeError
针对您的具体情况,最直接的解决方案可能是简单地允许非序列 return 类型,并使用 Callable
而不是 Type
。
T, R = TypeVar('T'), TypeVar('R')
def chain_into(into: Callable[[Iterable[T]], R], *iters: Iterable[T]) -> R:
return into(chain.from_iterable(iters))
我想编写以下通用 Python 代码:
from itertools import chain
from typing import Sequence, Hashable, List, Tuple, Type, TypeVar
SequenceT = TypeVar('SequenceT', bound=Sequence)
HashableT = TypeVar('HashableT', bound=Hashable)
def merge_and_sort_into(seq_type, *iterables):
# type: (Type[SequenceT], *Iterable[HashableT]) -> SequenceT[HashableT]
return seq_type(sorted(set(chain(*iterables))))
def merge_and_sort_into_list(*iterables):
# type: (*Iterable[HashableT]) -> List[HashableT]
return merge_and_sort_into(list, *iterables)
def merge_and_sort_into_tuple(*iterables):
# type: (*Iterable[HashableT]) -> Tuple[HashableT]
return merge_and_sort_into(tuple, *iterables)
代码很好,但是 mypy 不喜欢 merge_and_sort_into()
的 return 类型说 error: Type variable "SequenceT" used with arguments
。如何将 Sequence 类型传递给函数并将该类型用作 return 类型? (注意:我没有捕捉到序列的值类型也需要是 comparable/sortable 的事实,但让我们忽略它)。
这是 mypy 将接受的版本,但它没有捕获传递给 merge_and_sort_into()
的类型是它的 return 类型的约束,因此是强制转换。
def merge_and_sort_into(seq_type, *iterables):
# type: (Callable[[Iterable[HashableT]], Sequence[HashableT]], *Iterable[HashableT]) -> Sequence[HashableT]
return seq_type(sorted(set(chain(*iterables))))
def merge_and_sort_into_list(*iterables):
# type: (*Iterable[HashableT]) -> List[HashableT]
return cast(List[HashableT], merge_and_sort_into(list, *iterables))
def merge_and_sort_into_tuple(*iterables):
# type: (*Iterable[HashableT]) -> Tuple[HashableT]
return cast(Tuple[HashableT], merge_and_sort_into(tuple, *iterables))
Mypy 不支持泛型类型变量,因为它们需要类型系统支持更高种类,如 this comment 中所述。
即使 Mypy 支持泛型类型变量,原始函数的类型签名也会不正确,因为并非所有 Sequence
都可以从可迭代对象构造。例如,
class EmptyList(Sequence[T]):
def __init__(self): pass
def __getitem__(self, item): raise IndexError
def __len__(self): return 0
EmptyList([1, 2, 3]) # TypeError
针对您的具体情况,最直接的解决方案可能是简单地允许非序列 return 类型,并使用 Callable
而不是 Type
。
T, R = TypeVar('T'), TypeVar('R')
def chain_into(into: Callable[[Iterable[T]], R], *iters: Iterable[T]) -> R:
return into(chain.from_iterable(iters))