繁体   English   中英

我应该如何类型提示调用另一个 class 方法来构造 class 实例的通用 class 方法?

[英]How should I type-hint a generic class method that calls another class method to construct an instance of the class?

我试图找出几个抽象类的类型提示,我想将它们用作类的基类, create function。具体来说,这是用于反序列化类型。

我的简单示例如下所示

from abc import ABC, abstractmethod
from typing import Type, TypeVar


T = TypeVar("T", bound="A")


class A(ABC):
    @classmethod
    @abstractmethod
    def create(cls: Type[T]) -> T:
        pass

class B(A, ABC):
    @classmethod
    @abstractmethod
    def create_b(cls: Type[T]) -> T:
        pass

    @classmethod
    def create(cls) -> T:
        return cls.create_b()

当我针对这个运行 Mypy 时,我得到

错误:不兼容的返回值类型(得到“B”,应为“T”)

我对此感到困惑,因为B继承自A ,我认为T或多或少代表“任何A ”。

我可以将倒数第二行更改为

    def create(cls: Type[T]) -> T:

但后来我明白了

错误:“Type[T]”没有属性“create_b”

我应该怎么做才能让 mypy 通过?

由于create是 class 方法,因此参数cls的类型为Type[B] 这意味着create_b中为参数和返回类型指定的T将解析为B ,因此表达式cls.create_b()的类型为B 这会导致您收到错误。

这里令人困惑的部分可能是因为BA的子类型并且T绑定到A ,所以人们可能期望应该可以在B.create()中返回B 然而,问题是,当B.create()在某些上下文中使用而不是更早时, T将得到解决。 在您的示例中,您已经隐式地将T强制为B ,这可能会导致类型错误。

例如,假设我们创建以下 class 和 function。

class C(A):
    pass


def foo(x: C):
    pass

我们现在可以使用B.create()作为foo的参数:

foo(B.create())

类型检查器不会在这里抱怨,因为它解析Tcreate的通用返回类型为C ,这非常好,因为TA绑定,而CA的子类型。

重新审视B.create()的 function 定义,我们现在可以看到我们实际上必须返回抽象类型T而不是T的某些允许的实现,例如B (甚至A )。

长话短说

您可以通过更改B.create()的返回类型来修复错误:

@classmethod
def create(cls) -> "B":
    return cls.create_b()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM