我试图为以下函数(python3.6,mypy0.521)提供完美的函数签名:
def avg(xs):
it = iter(xs)
try:
s = next(it)
i = 1
except StopIteration:
raise ValueError("Cannot average empty sequence")
for x in it:
s += x
i += 1
return s / i
这段代码的好处是,它可以与int
,float
,complex
的iterables生成正确的结果,也可以为datetime.timedelta
生成正确的结果。尝试添加签名时会出现问题。我试过以下方法:
但现在,调用者需要转换结果。在
def avg(xs: t.Iterable[T]) -> T: ...
此操作失败,因为T
不支持加法或除法。在
N = TypeVar("N", int, float, complex, datetime.timedelta)
def avg(xs: t.Iterable[N]) -> N: ...
失败的原因是int / int
是float
;使用//
对几乎所有其他内容都给出了错误的结果。也很糟糕,因为只要支持加法和除法,代码就可以用于其他类型。在
N = TypeVar("N", float, complex, datetime.timedelta)
def avg(xs: t.Iterable[N]) -> N: ...
这几乎是完美的,但是,如果后来有人决定用四元数来表示,mypy会抱怨的。在
…然后我也在尝试使用abc
和{
在mypy --strict
下通过的最优雅的解决方案是什么?在
因此,不幸的是,Python/pep484中的数字系统目前有点混乱。在
从技术上讲,我们有一个"numeric tower"来表示一组abc,Python中所有“类似数字”的实体都应该遵守这些abc。在
在这种情况下,{cd3}基本上都是从这些自定义类型继承而来的。在
为了解决这个问题,我在大约一年前,在typeshed中的numbers module is largely dynamically typed曾尝试过修复数字模块,而我的记忆是当时的mypy不够强大,无法准确地键入数字塔。在
这种情况今天可能已经解决了,但这或多或少都是没有意义的,因为mypy最近实现了对协议的实验性支持(例如结构类型)!事实证明,这正是我们需要解决的问题,并最终修复数字塔(一旦协议被添加到pep484和输入模块中)。在
目前,您需要做的是:
typing_extensions
模块(python3 -m pip install typing_extensions
)python3 -m pip install -U git+git://github.com/python/mypy.git
)然后,我们可以为“支持加法或除法”类型定义一个协议,如下所示:
根据需要,使用mypy运行此命令将生成以下输出:
^{2}$相关问题 更多 >
编程相关推荐