关于使类型注释与__round__
一起使用的在线信息并不多。我已经实现了这一点,但是在运行mypy时,仍然在第16行(在没有round
参数的情况下调用ndigits
时出现错误:
错误:分配中的类型不兼容(表达式的类型为“ int”,变量的类型为“ MyClass”)
测试通过,即在两次调用round
的过程中,我都返回了MyClass
类型的对象。但是只有当我不带参数调用round
时,MyPy检查才会失败。
版本号:Python 3.6.5,mypy 0.641。
from typing import Any, SupportsRound, overload
class MyClass(SupportsRound['MyClass']):
def __round__(self: 'MyClass', ndigits: int = 0) -> 'MyClass':
return self
def test_tmp() -> None:
x = MyClass()
result: MyClass
result = round(x, 0)
assert type(result) == MyClass
result = round(x)
assert type(result) == MyClass
答案 0 :(得分:1)
我认为这里的问题与您使用SupportsRound
的关系较小,而与round
函数的定义的关系更大。 round
函数在typeshed(标准库类型提示的存储库)中定义,以具有the following signature:
@overload
def round(number: float) -> int: ...
@overload
def round(number: float, ndigits: None) -> int: ...
@overload
def round(number: float, ndigits: int) -> float: ...
@overload
def round(number: SupportsRound[_T]) -> int: ...
@overload
def round(number: SupportsRound[_T], ndigits: None) -> int: ... # type: ignore
@overload
def round(number: SupportsRound[_T], ndigits: int) -> _T: ...
请注意,当仅提供一个参数或ndigits
为None时,输出始终为int
。这与标准库https://docs.python.org/3/library/functions.html#round
round
函数的已记录行为一致。
不幸的是,我没有一种真正干净的方法来解决此问题:我不认为implementation of SupportsRound与这种行为确实一致。
具体来说,应该将SupportsRound定义如下:
@runtime
class SupportsRound(Protocol[_T_co]):
@abstractmethod
@overload
def __round__(self, ndigits: None = None) -> int: ...
@abstractmethod
@overload
def __round__(self, ndigits: int) -> _T_co: ...
基本上,强迫用户处理这两种情况。
实际上,更改定义可能会很复杂:实际上并没有一种干净的方法来更新与旧版本的打字模块捆绑在一起的所有旧版本的Python。
我建议在已解决的问题跟踪器中提交与此有关的问题。我个人认为您在这里发现了一个真正的不一致/错误,但是这里可能遗漏了一些细微差别,所以我认为将其升级是很好的。