类型提示 Python 枚举静态方法,其中定义了文字类型

问题描述 投票:0回答:1

在下面的代码中,

direction
数据类的
Horizontal
属性被类型提示为仅允许来自
Direction
枚举的5个值中的3个。我希望能够使用
from_string
静态方法从动态输入返回枚举值,如果字符串与任何枚举值都不匹配,则该方法会回退到 Direction.UNKNOWN 。实际上,代码可以工作,但
mypy
抱怨以下错误:

27:错误:赋值中的类型不兼容(表达式的类型为“Direction”,变量的类型为“Literal[Direction.LEFT,Direction.RIGHT,Direction.UNKNOWN]”)[赋值] 在 1 个文件中发现 1 个错误(检查了 1 个源文件)

这是可以理解的,因为我们从静态方法返回一个通用的

Direction
实例,而不是类型提示的特定 3 个实例之一。除了删除
mypy
方法的返回类型之外,还有什么方法可以满足
from_string
的要求吗?

from dataclasses import dataclass
from enum import auto, StrEnum
from typing import Literal

class Direction(StrEnum):
    DOWN = auto()
    LEFT = auto()
    RIGHT = auto()
    UP = auto()
    UNKNOWN = auto()

    @staticmethod
    def from_string(value: str) -> 'Direction':
        try:
            return Direction(value.lower())
        except ValueError:
            pass
        return Direction.UNKNOWN

@dataclass
class Horizontal:
    direction: Literal[Direction.LEFT, Direction.RIGHT, Direction.UNKNOWN] = Direction.UNKNOWN

horizontal = Horizontal()
horizontal.direction = Direction.LEFT
print(f'{horizontal=}')
horizontal.direction = Direction.from_string(input('Enter a direction: '))
print(f'{horizontal=}')
python mypy python-typing
1个回答
1
投票

尝试定义新的枚举作为整个枚举的子集:

from enum import auto, StrEnum


class Direction(StrEnum):
    LEFT = auto()
    RIGHT = auto()
    UP = auto()
    DOWN = auto()
    UNKNOWN = auto()


Horizontal = StrEnum("Horizontal", [(Direction.LEFT.name, Direction.LEFT),
                                 (Direction.RIGHT.name, Direction.LEFT),
                                 (Direction.UNKNOWN.name, Direction.UNKNOWN)])
Vertical = StrEnum("Vertical", [(Direction.UP.name, Direction.UP),
                             (Direction.DOWN.name, Direction.DOWN),
                             (Direction.UNKNOWN.name, Direction.UNKNOWN)])


my_direction: Horizontal = Horizontal.LEFT
print(f'{my_direction=}')
my_direction = Horizontal[input('Enter a direction: ')]
print(f'{my_direction=}')

这将使您能够在代码中适当的地方使用子集并保持正确的输入。在这种情况下,如果用户尝试输入“向上”或“向下”,则会引发异常,我认为这就是您想要的。这是运行时检查,而不是 mypy 检查。

© www.soinside.com 2019 - 2024. All rights reserved.