我試圖想出以下功能完善的函數簽名(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