强制类型标识的默认参数

Default argument enforcing type identity

我有自定义 class(实际上是 heapq 的简单包装器),它将接口包装成面向对象的接口并允许可选的 keycmp 参数。

为了实现类型检查,我引入了 Tv(堆中的值类型)和 Tk("keys" 值的类型——即要执行的操作在堆内进行比较)。

因此 __init__ 的注释如下所示:

from typing import *

Tv = TypeVar('Tv')
Tk = TypeVar('Tk')

class Heap(Generic[Tv, Tk]):
    def __init__(self, initial: Optional[Iterable[Tv]],
                 key: Callable[[Tv], Tk] = lambda x: x, cmp: Callable[[Tk, Tk], bool] = op.lt):
        pass

不幸的是,mypy 在这种情况下报告和错误:

error: Incompatible default for argument "key" (default has type "Callable[[Tv], Tv]", argument has type "Callable[[Tv], Tk]")

由于 Tk 的规范对于任何要使用 Heap 的人来说都没什么用,我试图完全放弃它——我制作了 Heap subclass 只是 Generic[Tv] 并设置 Tk = Any。这有很好的副作用,Heap 的用户不需要指定 Tk 类型,这与 Tv 基本相同,但我丢失了 [=16] 上的所有类型检查=] 在我的实现中。

有没有办法在 Heap 中保持 Tk 的类型检查并使 lambda x: x 的默认键值不引发错误?

编辑:当我试图使 Heap subclass 只是 Generic[Tv] 并保留 Tk = TypeVar('Tk') 时,我仍然遇到错误

lambda x: x 的推断类型是 Callable[[Tv], Tv],因为函数中没有任何内容可以在 return 之前更改 x 的类型。这违反了类型提示,即参数和 return 类型可以任意变化。

解决方法是使用 cast 告诉 mypy 默认函数可以根据需要 "change" 其参数类型。

class Heap(Generic[Tv, Tk]):
    def __init__(self, 
                 initial: Optional[Iterable[Tv]],
                 key: Callable[[Tv], Tk] = lambda x: <b>cast(Tk, x)</b>,
                 cmp: Callable[[Tk, Tk], bool] = op.lt):
        pass

然而,这基本上告诉 mypy 你知道自己在做什么,如果没有提供 key 函数,那么 you将确保 Tv 类型的值实际上可以用作 Tk 类型的值。通常,对于任意类型 TvTk.

,没有 类型为 Callable[[Tv], Tk] 的函数