寻找一个'SupportsRou nd`的工作示例

问题描述 投票:3回答:1

网上没有很多关于使用__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
python mypy
1个回答
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。这与round函数在标准库中记录的行为一致:https://docs.python.org/3/library/functions.html#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。

我建议在类型化问题跟踪器上提交有关此问题的问题。我个人认为你在这里发现了一个真正的不一致/错误,但这里可能存在一些细微差别我不知道,所以我认为升级它会很好。

© www.soinside.com 2019 - 2024. All rights reserved.