提问人:J.N. 提问时间:10/5/2023 最后编辑:mkrieger1J.N. 更新时间:10/6/2023 访问量:65
带悬垂的成对提示类型
Type hinting pairwise with overhang
问:
我接管了一个代码库(支持低至 3.9),并想添加一些类型提示。但是,我目前被困在此功能上。
def _pairwise(iterable: T.Iterable, end=None) -> T.Iterable:
left, right = itertools.tee(iterable)
next(right, None)
return itertools.zip_longest(left, right, fillvalue=end)
稍后用于迭代正则表达式匹配并提取其开始和结束索引以进行切片。的最后一个填充值用于将最后一个切片转到字符串的末尾。None
我们知道实际签名应该是
_pairwise(iterable: Iterable[T], end: Optional[T] = None) -> Iterator[tuple[T, Optional[T]]]
因为保证至少和 .left
right
但是,带有 的方法不允许这样做。类型检查器将其读取为 .zip_longest
Iterator[Optional[T], Optional[T]]
我重写了该函数,以便类型检查器(pyright)能够验证该目标签名。
def _pairwise(
iterable: Iterable[T], end: Optional[T] = None
) -> Iterator[tuple[T, Optional[T]]]:
left, right = itertools.tee(iterable)
next(right, None)
for x, y in zip(right, left):
yield y, x
if (last := next(left, None)) is not None:
yield last, end
但是,我对这个结果还不是特别满意。首先,需要交换参数以避免它采取额外的步骤,以及手动检查以处理参数是空迭代对象的情况。zip
left
这也意味着该功能不是预期的功能,尽管这实际上不是问题,但它确实让我有点恼火。T=NoneType
有没有其他方法可以让这个成对功能进行类型检查?
答:
您的解决方案对我来说看起来很干净,并且非常适合那里,可能会有一个简短的解释性评论。zip_longest
# type: ignore[return-value]
但是,要进行代码类型检查,您可以使用 plain 并在末尾手动添加“filler”条目,如下所示:zip
import itertools
from typing import Iterable, Iterator, TypeVar, Optional
T = TypeVar('T')
def _pairwise(
iterable: Iterable[T], end: Optional[T] = None
) -> Iterator[tuple[T, Optional[T]]]:
left, right = itertools.tee(iterable)
next(right, None)
return zip(left, itertools.chain(right, [end]))
现在对这段代码很满意,而且你稍微明确一点:你知道第二个可迭代 () 比 unless is empty 短一个元素,因此附加一个项目将使它们相等。如果输入为空,则两个实现都会生成一个空迭代器。mypy
right
left
iterable
评论
yield from
for...yield
itertools.chain
[end]
zip
left
zip_longest