我试图想出以下功能完善的函数签名(Python的3.6,mypy 0.521):Mypy:寻找完美的签名,平均功能
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
,以及datetime.timedelta
的迭代结果一起工作并产生正确的结果。尝试添加签名时弹出问题。我试过以下内容:
def avg(xs: t.Iterable[t.Any]) -> t.Any: ...
但现在,调用者需要施放结果。
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
和typing.overload
,但这让我无处可寻。
什么是在mypy --strict
下可以通过的最优雅的解决方案?
好像浮/ INT不对称意味着你真的不能创建此一致的签名。它产生“正确的结果”,在数字意义上,对于整型和浮点,但'AVG([整数列表])'产生浮动,同时'AVG([浮点值列表])'还产生浮动。这意味着你的函数有时会返回它给相同的类型,有时另一种类型,所以它没有返回类型在其输入类型方面一致定义。 mypy是否允许像“number”这样的类型(如'numbers.Number')? – BrenBarn
疯狂的是,'numbers.Number'没有定义'__add__'或其他标准的算术运算,所以我得到'不支持的左操作数类型+(“数字”)','不支持的操作类型/(“数字”和“INT”)'等 – rollcat