【问题标题】:Looking for a working example of `SupportsRound`寻找“SupportsRou​​nd”的工作示例
【发布时间】:2019-04-28 03:27:12
【问题描述】:

网上没有很多关于使类型注释与__round__ 一起工作的详细信息。我已经实现了这一点,但是当我运行 mypy 时,我仍然在第 16 行遇到错误(在没有 ndigits 参数的情况下调用 round):

错误:赋值类型不兼容(表达式类型为“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】:

    我认为这里的问题与您对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 为无时,输出始终为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。

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

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 2020-11-11
      • 2022-11-07
      • 1970-01-01
      • 2016-12-09
      • 1970-01-01
      • 2012-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多