寻找`SupportsRou​​nd`的工作示例

时间:2018-11-26 13:12:08

标签: python mypy

关于使类型注释与__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

1 个答案:

答案 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与这种行为确实一致。

具体来说,应该将SupportsRou​​nd定义如下:

@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。

我建议在已解决的问题跟踪器中提交与此有关的问题。我个人认为您在这里发现了一个真正的不一致/错误,但是这里可能遗漏了一些细微差别,所以我认为将其升级是很好的。