网上没有很多关于使类型注释与 __round__
一起工作的详细信息。我已经实现了这个但是当我运行 mypy 时我仍然在第 16 行(调用 round
没有 ndigits
参数)出现错误:
error: Incompatible types in assignment (expression has type "int", variable has type "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
最佳答案
我相信这里的问题与您对 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
。这与标准库中记录的 round
函数行为一致:https://docs.python.org/3/library/functions.html#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。
我建议在 typeshed issue tracker 上提交关于此的问题。我个人认为您在这里发现了一个真正的不一致/错误,但这里可能存在一些我遗漏的细微差别,所以我认为最好将其升级。
关于python - 寻找 `SupportsRound` 的工作示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53481887/