可以使用Mypy给fold_left()输入类型吗?

问题描述 投票:1回答:1

我有一个简单的左折功能,如下:

from typing import Iterable, Callable, Optional, TypeVar, overload


S = TypeVar("S")
T = TypeVar("T")


def fold_left(it: Iterable[S], f: Callable[[T, S], T], init: Optional[T] = None) -> T:
    it = iter(it)

    if init is None:
        try:
            acc = next(it)
        except StopIteration:
            raise ValueError("fold_left given empty iterable with no init")
    else:
        acc = init

    for i in it:
        acc = f(acc, i)

    return acc

Mypy在检查该代码时抛出以下错误:

10: error: Incompatible types in assignment (expression has type "T", variable has type "S")
13: error: Incompatible types in assignment (expression has type "T", variable has type "S")
13: error: Argument 1 has incompatible type "S"; expected "T"
15: error: Incompatible return value type (got "S", expected "T")

[Mypy似乎不喜欢这样的事实,当init is None时,类型S和T将相同。是否有某种方法可以使代码正确输入以便正确键入检查?

我尝试使用以下行进行重载,但没有任何效果:

@overload
def fold_left(it: Iterable[S], f: Callable[[T, S], T], init: T) -> T:
    ...


@overload
def fold_left(it: Iterable[S], f: Callable[[S, S], S]) -> S:
    ...
python mypy
1个回答
0
投票

这个问题有两个部分。

首先,对函数的外部接口进行类型检查。这是与overload相关的地方。

@overload
def fold_left(it: Iterable[S], f: Callable[[T, S], T], init: T) -> T:
    ...


@overload
def fold_left(it: Iterable[S], f: Callable[[S, S], S]) -> S:
    ...

这指定了函数的所有有效签名。

但是,这((直接)对我们函数的类型检查没有帮助。我们需要独立解决此问题。

def fold_left(it: Iterable[S], f: Callable[[T, S], T], init: Optional[T] = None) -> T:
    # we can't change the type of it which is already defined to be an 
    # `Iterable`, so in order for `next` to type check we need a new 
    # variable of type `Iterator` 
    itor: Iterator[S] = iter(it) 

    # acc contains or return value it therefore has to be of type `T`
    acc: T

    if init is None:
        try:
            # mypy isn't smart enough to figure out that if `init` is 
            # `None`, then `S` is equal to `T`, we therefore need to tell it
            # that this assignment is correct
            acc = cast(T, next(itor)) 
        except StopIteration:
            raise ValueError("fold_left given empty iterable with no init")
    else:
        acc = init

    for i in itor:
        acc = f(acc, i)

    return acc

overload语句确实间接地帮助了我们,因为它们以某种方式限制了我们函数的公共接口,使我们可以推断我们在实现中使用的cast是正确的。

© www.soinside.com 2019 - 2024. All rights reserved.