Python 是否可以使用Mypy为fold_left()指定一个类型?
我有一个简单的左折叠函数,如下所示:Python 是否可以使用Mypy为fold_left()指定一个类型?,python,mypy,Python,Mypy,我有一个简单的左折叠函数,如下所示: 输入import-Iterable、Callable、Optional、TypeVar、重载 S=类型变量(“S”) T=类型变量(“T”) def fold_left(it:Iterable[S],f:Callable[[T,S],T],init:Optional[T]=None)->T: it=国际热核实验堆(iter) 如果init为None: 尝试: acc=下一个(it) 除停止迭代外: raise VALUE ERROR(“左折叠,给定无初始的空
输入import-Iterable、Callable、Optional、TypeVar、重载
S=类型变量(“S”)
T=类型变量(“T”)
def fold_left(it:Iterable[S],f:Callable[[T,S],T],init:Optional[T]=None)->T:
it=国际热核实验堆(iter)
如果init为None:
尝试:
acc=下一个(it)
除停止迭代外:
raise VALUE ERROR(“左折叠,给定无初始的空iterable”)
其他:
acc=init
对我来说:
acc=f(acc,i)
返回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为None
时,类型S和t将是相同的。有没有办法欺骗代码,使其正确地键入check
我尝试使用以下行重载,但没有效果:
@重载
def fold_left(it:Iterable[S],f:Callable[[T,S],T],init:T)->T:
...
@超载
def fold_left(it:Iterable[S],f:Callable[[S,S],S])->S:
...
这个问题分为两部分
首先,对函数的外部接口进行类型检查。这就是与过载相关的地方
@重载
def fold_left(it:Iterable[S],f:Callable[[T,S],T],init:T)->T:
...
@超载
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
重载
语句确实间接地帮助了我们,因为它们限制了我们函数的公共接口,使我们能够推断我们在实现中使用的强制转换
是正确的。这个问题有两个部分
首先,对函数的外部接口进行类型检查。这就是与过载相关的地方
@重载
def fold_left(it:Iterable[S],f:Callable[[T,S],T],init:T)->T:
...
@超载
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
重载
语句确实间接地帮助了我们,因为它们以某种方式限制了我们函数的公共接口,允许我们推断我们在实现中使用的强制转换
是正确的。acc
(typet
)不会与it
(typeIterable[S]
)中的值的类型相同不管例如,fold_left([1,2,3,4],add)
将返回类型为int
的值,[1,2,3,4]
是包含类型为int
的值的iterable,在许多情况下,T
和S
是同一类型。acc
仅在未指定init
时才是S
类型。如果指定了init
,acc
可以是另一种类型。考虑下面的行,其中代码< >代码>列表[INT] 和<代码> ACC 类型为<代码> STR >:<代码> FordDeLead([1, 2, 3),lambda x,y:x+STR(y),“”)“∧=>123”< /Cord>超载是IMO的去路。这有什么问题?请注意,mypy
不能假定T
和s
是相同的。静态键入意味着所有T
,S
(包括T!=S
)的代码必须正确,而不是任何T
,S
(不包括T!=S
的代码)。函数本身必须具有良好的类型,而不考虑一些具体的、动态的f
或init
值将其限制为有效的行为。那么acc
(typet
)是否与it
(typeIterable[S]
)中的值具有相同的类型呢?例如,fold_left([1,2,3,4],add)
将返回类型为int
的值,[1,2,3,4]
是包含类型为int
的值的iterable,在许多情况下,T
和S
是同一类型。acc
仅在未指定init
时才是S
类型。如果指定了init
,acc
可以是另一种类型。考虑下面的行,其中代码< >代码>列表[INT] 和<代码> ACC 类型为<代码> STR >:<代码> FordDeLead([1, 2, 3),lambda x,y:x+STR(y),“”)“∧=>123”< /Cord>超载是IMO的去路。这有什么问题?请注意,mypy
不能假定T
和s
是相同的。静态键入意味着所有T
,S
(包括T!=S
)的代码必须正确,而不是任何T
,S
(不包括T!=S
的代码)。函数本身必须具有良好的类型,而不考虑某些具体的动态f
或init
值将其限制为有效行为。