子类中返回值的类型提示

我正在编写一个 CustomEnum 类,我想在其中添加一些辅助方法,然后子类化我的 CustomEnum 的类可以使用这些方法。其中一种方法是返回一个随机枚举值,这就是我被卡住的地方。该函数按预期工作,但在类型提示方面,我无法想出一种说法“返回类型与 cls 类型相同”

我相当确定其中TypeVar涉及一些或类似的魔法,但由于我从未使用过它们,因此我从未花时间弄清楚它们。

class CustomEnum(Enum):
    @classmethod
    def random(cls) -> ???:
        return random.choice(list(cls))


class SubclassingEnum(CustomEnum):
    A = "a"
    B = "b"

random_subclassing_enum: SubclassingEnum
random_subclassing_enum = SubclassingEnum.random() # Incompatible types in assignment (expression has type "CustomEnum", variable has type "SubclassingEnum")

有人可以帮助我或给我一个关于如何进行的提示吗?

谢谢!

回答

这里的语法有点可怕,但我认为没有更简洁的方法来做到这一点。

from typing import TypeVar
from enum import Enum

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

class CustomEnum(Enum):
    @classmethod
    def random(cls: type[T]) -> T:
        return random.choice(list(cls))

(在 python 版本 <= 3.8 中,如果要对其进行参数化,则必须使用typing.Type而不是内置type函数。)

这里发生了什么?

T在顶部定义为“绑定”到CustomEnum类的类型变量。这意味着用 注释的变量T只能是CustomEnum从 继承的类的实例或实例CustomEnum

在上面的类方法中,我们实际上是使用这个类型变量来定义cls与返回类型相关的参数类型。通常我们做相反的事情——我们通常根据函数的输入参数的类型定义函数的返回类型。因此,如果这感觉有点令人费解,这是可以理解的!

我们是说:这个方法会导致一个类的实例——我们不知道这个类会是什么,但我们知道它会是或者是CustomEnum一个继承自 的类CustomEnum。我们也知道,无论返回什么类,我们都可以保证cls函数中参数的类型在类型层次结构中比返回值的类型“上一层”。

在很多情况下,我们可能知道这type[cls]将始终是一个固定值。在这些情况下,可以将其硬编码到类型注释中。但是,最好要这样做,而是使用这种方法,它清楚地显示了输入类型和返回类型之间的关系(即使它使用了可怕的语法来这样做!)。

进一步的解释和例子

对于绝大多数类(不使用Enums,它们使用元类,但让我们暂时将其搁置一旁),以下内容将适用:

示例 1

Class A:
    pass

instance_of_a = A()
type(instance_of_a) == A # True
type(A) == type # True

例子2

class B:
    pass

instance_of_b = B()
type(instance_of_b) == B # True
type(B) == type # True

对于cls你的参数CustomEnum.random()的方法,我们标注的等效A,而不是instance_of_a在我的例子1以上。

  • 的类型instance_of_aA
  • 但类型A不是A——A是一个类,而不是一个类的实例。
  • 类不是类的实例;它们是type继承自 的自定义元类的实例或实例type
  • 这里没有使用元类;因此, 的类型Atype

规则如下:

  • 所有 python类实例的类型将是它们所属的类。
  • 所有 python类的类型将是type或者(如果你对自己的好处太聪明了)继承自type.

有了您的CustomEnum类,我们可以注释cls与元类,参数enum模块使用(enum.EnumType,如果你想知道)。但是,正如我所说 - 最好不要。我建议的解决方案更清楚地说明了输入类型和返回类型之间的关系。


以上是子类中返回值的类型提示的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>