Python 如何使用默认函数键入zip_

Python 如何使用默认函数键入zip_,python,type-hinting,Python,Type Hinting,如何键入此函数,根据某个函数来压缩映射值 K = TypeVar("K") U = TypeVar("U") V = TypeVar("V") W = TypeVar("W") def zip_with( u: Mapping[K, U], v: Mapping[K, V], f: Callable[[U, V], W] = lambda u, v: (u, v) ) -> Mapp

如何键入此函数,根据某个函数来压缩映射值

K = TypeVar("K")
U = TypeVar("U")
V = TypeVar("V")
W = TypeVar("W")


def zip_with(
    u: Mapping[K, U],
    v: Mapping[K, V],
    f: Callable[[U, V], W] = lambda u, v: (u, v)
) -> Mapping[K, W]:
    return {k: f(u[k], v[k]) for k in u}
我要走了

utils/misc.py:66:错误:参数“f”的默认值不兼容(默认值的类型为“Callable[[U,V],Tuple[U,V]]”,参数的类型为“Callable[[U,V],W]”)
utils/misc.py:66:错误:返回值类型不兼容(获取“Tuple[U,V]”,应为“W”)
Afaik mypy无法通过默认参数推断类型签名,但重载可以帮助。然而,我看不出你如何在不丢失某个类型安全性的情况下做到这一点,因为如果
f
的默认值不是函数,那么就无法创建
W
例如

@overload
def zip_with(u: Mapping[K, U], v: Mapping[K, V]) -> Mapping[K, Tuple[U, V]]:
    ...


@overload
def zip_with(
    u: Mapping[K, U],
    v: Mapping[K, V],
    f: Callable[[U, V], W]
) -> Mapping[K, W]:
    ...


def zip_with(
    u: Mapping[K, U],
    v: Mapping[K, V],
    f: Optional[Callable[[U, V], W]] = None
) -> Mapping[K, W]:
    if f is None:
        return {k: (u[k], v[k]) for k in u}

    return {k: f(u[k], v[k]) for k in u}
给予


f
的默认值是
lambda u,v:(u,v)
,它的返回值为
Tuple[无论u是什么,无论v是什么]
,但是您在它们的类型提示中指定
可调用[[u,v],W]
返回值应该是
W


如果
Tuple[U,V]
属于
W
类型,那么你对
W
的定义应该证明这一点
W=Tuple[U,V]

我不理解你所说的“你对W的定义应该证明这一W=Tuple[U,V]”。我不确定这是否可能,因为返回类型中的
W
可能是由输入中的
W
绑定的,但如果没有
f
,则根本不绑定,因此我们不能符合不存在的类型>返回类型可能是由输入@joel中的W绑定的,我不明白你的意思,正如您当前将W全局定义为
W=TypeVar(“W”)
。这个定义与
Tuple[U,V]
您从默认值
lambda U,V:(U,V)
返回的Tuple[U,V]相矛盾,我认为它并不矛盾,但它限制了它,并且以一种有效的方式,就像我将
lambda
作为参数传递一样,我希望mypy推断
W
Tuple[U,V]
在这种情况下,scala编译中的等效代码很好,这不是一个非常令人满意的答案,但通常在键入像这样的棘手内容时,我会在实际实现函数中键入一个
Any
#键入:ignore
,然后编写大量的单元测试来证明它实际上遵守了类型重载指定的契约。@Samwise我可以通过
@重载
并在实现签名中将
W
设置为
Any
,同时保持
lambda
默认值来实现非常接近的效果
utils/misc.py:81: error: Value expression in dictionary comprehension has incompatible type "Tuple[U, V]"; expected type "W"