【问题标题】:Python typing signature for instance of subclass?子类实例的Python类型签名?
【发布时间】:2021-01-30 10:04:33
【问题描述】:

考虑:

from __future__ import annotations

class A:
    @classmethod
    def get(cls) -> A:
        return cls()

class B(A):
    pass

def func() -> B: # Line 12
    return B.get()

运行 mypy 得到:

$ mypy test.py
test.py:12: error: Incompatible return value type (got "A", expected "B")
Found 1 error in 1 file (checked 1 source file)

此外,我已经检查过旧式递归注释是否有效。那就是:

# from __future__ import annotations

class A:
    @classmethod
    def get(cls) -> "A":
# ...

...无济于事。

当然可以:

from typing import cast

def func() -> B: # Line 12
    return cast(B, B.get())

每次出现这种情况。但我想避免这样做。

应该如何输入这个?

【问题讨论】:

  • 我不确定你在问什么。如果你想返回A,你需要明确地转换它。如果您只想正确地对函数进行类型注释,为什么不def func() -> A
  • 我实际上想在func 中返回B。例如,假设我们有代表数据库实体的类。我们有一个公共类Entity 和子类UserProject。这些子类还具有其他重要的特殊属性。我们希望明确说明您是返回 User 还是 Project,因为这会限制我们在下游可以做的事情。

标签: python mypy python-typing


【解决方案1】:

clsself 参数通常由mpyp 推断,以避免大量冗余代码,但在需要时可以通过注释显式指定它们。

在这种情况下,类方法的显式类型如下所示:

class A:
    @classmethod
    def get(cls: Type[A]) -> A:
        return cls()

所以我们这里真正需要的是将Type[A] 设为泛型参数,这样当从子类调用类方法时,您可以改为引用子类。幸运的是,我们有 TypeVar 值。

将其应用到您现有的示例中,我们将得到以下结果:

from __future__ import annotations

from typing import TypeVar, Type


T = TypeVar('T')


class A:
    @classmethod
    def get(cls: Type[T]) -> T:
        return cls()


class B(A):
    pass


def func() -> B:
    return B.get()

现在mypy 应该再次成为你的朋友! ?

【讨论】:

    猜你喜欢
    • 2013-06-10
    • 1970-01-01
    • 1970-01-01
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    相关资源
    最近更新 更多