我有一个自定义的类(其实是简单的包装,用于 heapq
),它将接口包装成面向对象的接口,并允许可选的 key
和 cmp
参数。
为了实现类型检查,我引入了 Tv
(堆内值的类型)和 Tk
值的 "键 "的类型--即在堆内要比较的东西)。
因此,对 __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
子类 Generic[Tv]
并设置 Tk = Any
. 这有一个很好的副作用,即用户的。Heap
就不需要说明 Tk
型,这与 Tv
但我失去了所有的类型检查 Tk
在我的实现中。
是否有办法让类型检查保持在 Tk
之内 Heap
并使默认键值为 lambda x: x
不提出一个错误?
编辑:当我试图使 Heap
子类 Generic[Tv]
并保持 Tk = TypeVar('Tk')
我仍然得到了错误
推断的类型 lambda x: x
是 Callable[[Tv], Tv]
的类型,因为函数中没有任何东西可以改变 x
的类型,然后再返回它。这违反了类型提示,即参数和返回类型可以任意变化。
修正方法是使用 cast
告知 mypy
默认函数可以根据需要 "改变 "其参数类型。
class Heap(Generic[Tv, Tk]):
def __init__(self,
initial: Optional[Iterable[Tv]],
key: Callable[[Tv], Tk] = lambda x: cast(Tk, x),
cmp: Callable[[Tk, Tk], bool] = op.lt):
pass
然而,这基本上告诉 mypy
你知道你在做什么,如果你有一个。key
函数没有提供,那么 你 将确保类型为 Tv
实际上可以作为一个类型为 Tk
. 一般来说,有 没有 函数类型 Callable[[Tv], Tk]
对于任意类型 Tv
和 Tk
.