我正在编写一个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")有人能帮我吗?或者给我一个如何继续的提示?
谢谢!
发布于 2022-10-06 00:53:52
从Python3.11开始,这段代码的正确返回注释是Self
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声明。再一次,后一种代码的行为与前一种代码相当。
发布于 2021-07-07 09:10:27
这里的语法有点可怕,但我不认为有更干净的方法可以做到这一点。下面的通过MyPy
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
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()参数,我们在上面的示例1中注释等效的A而不是instance_of_a。
instance_of_a的类型是A。A的类型不是A -- A是一个类,不是一个类的实例。type的实例,要么是从type继承的自定义元类的实例。A的类型是type。规则如下:
type,要么是(如果您太聪明了)从type继承的自定义元类。使用CustomEnum类,我们可以用enum模块使用的元类(enum.EnumType,如果你想知道)注释cls参数。但是,就像我说的-最好不要。我提出的解决方案更清楚地说明了输入类型和返回类型之间的关系。
https://stackoverflow.com/questions/68282879
复制相似问题