首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在子类中键入返回值的提示

在子类中键入返回值的提示
EN

Stack Overflow用户
提问于 2021-07-07 08:48:49
回答 2查看 2.4K关注 0票数 10

我正在编写一个CustomEnum类,其中我想添加一些助手方法,然后通过子类CustomEnum来提供这些方法。其中一种方法是返回一个随机枚举值,这就是我被困的地方。函数按预期工作,但在类型提示方面,我无法找到一种方法来表示“返回类型是相同类型的cls”。

我很确定其中涉及到一些TypeVar或类似的魔法,但是由于我从来不用使用它们,所以我从来没有花时间去弄清楚它们。

代码语言:javascript
复制
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")

有人能帮我吗?或者给我一个如何继续的提示?

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-10-06 00:53:52

从Python3.11开始,这段代码的正确返回注释是Self

代码语言:javascript
复制
from typing import Self
class CustomEnum(Enum):
    @classmethod
    def random(cls) -> Self:
        return random.choice(list(cls))

引用PEP

这个PEP引入了一种简单直观的方法来注释返回类实例的方法。这与PEP 484中指定的基于TypeVar的方法相同,但更简洁,更易于遵循。 目前解决这一问题的方法是不直观的,而且容易出错: Self = TypeVar("Self",bound="Shape")类形状:@classmethod def from_config(cls: typeSelf,config:-> from_config)-> Self:返回cls(config"scale") 我们建议直接使用Self: 键入导入自类形状:@classmethod def from_config(cls,config:-> )-> Self:返回cls(config"scale") 这避免了复杂的cls: type[Self]注释和绑定的TypeVar声明。再一次,后一种代码的行为与前一种代码相当。

票数 1
EN

Stack Overflow用户

发布于 2021-07-07 09:10:27

这里的语法有点可怕,但我不认为有更干净的方法可以做到这一点。下面的通过MyPy

代码语言:javascript
复制
from typing import TypeVar
from enum import Enum
import random 

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的类的实例。

在上面的classmethod中,我们实际上使用这个类型变量来定义cls参数相对于返回类型的类型。通常我们做的相反-我们通常定义一个函数的返回类型相对于该函数的输入参数的类型。所以,如果这感觉有点扭曲,这是可以理解的!

我们的意思是:这个方法导致一个类的实例--我们不知道类是什么,但是我们知道它要么是CustomEnum,要么是继承自CustomEnum的类。我们还知道,无论返回什么类,我们都可以保证函数中的cls参数的类型与返回值的类型相比,在类型上是“一级上”的。

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

进一步阅读:关于MyPy的https://mypy.readthedocs.io/en/stable/kinds_of_types.html#the-type-of-class-objects文档。

进一步解释和实例

对于绝大多数类(不是Enum类,它们使用元类,但让我们暂时搁置一下),以下内容将是正确的:

示例1

代码语言:javascript
复制
Class A:
    pass

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

示例2

代码语言:javascript
复制
class B:
    pass

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

对于您的cls方法的CustomEnum.random()参数,我们在上面的示例1中注释等效的A而不是instance_of_a

  • instance_of_a的类型是A
  • 但是A的类型不是A -- A是一个类,不是一个类的实例。
  • 类不是类的实例;它们要么是type的实例,要么是从type继承的自定义元类的实例。
  • 这里没有使用元类;因此,A的类型是type

规则如下:

  • 所有python 类实例的类型将是它们的一个实例。
  • 所有python 的类型要么是type,要么是(如果您太聪明了)从type继承的自定义元类。

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

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68282879

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档