将字符串表示与使用整数值的枚举相关联?

新手上路,请多包涵

我正在尝试创建一个具有整数值的枚举,但它也可以为每个值返回一个显示友好的字符串。我在想我可以定义一个 dict 映射值到字符串,然后实现 __str__ 和一个带有字符串参数的静态构造函数,但是这有一个问题……

(在不同的情况下,我可以将此枚举的基础数据类型设置为字符串而不是整数,但这被用作枚举数据库表的映射,因此整数值和字符串都是有意义的,前者作为主键。)

 from enum import Enum

class Fingers(Enum):
    THUMB = 1
    INDEX = 2
    MIDDLE = 3
    RING = 4
    PINKY = 5

    _display_strings = {
        THUMB: "thumb",
        INDEX: "index",
        MIDDLE: "middle",
        RING: "ring",
        PINKY: "pinky"
        }

    def __str__(self):
        return self._display_strings[self.value]

    @classmethod
    def from_string(cls, str1):
        for val, str2 in cls._display_strings.items():
            if str1 == str2:
                return cls(val)
        raise ValueError(cls.__name__ + ' has no value matching "' + str1 + '"')

转换为字符串时,出现以下错误:

 >>> str(Fingers.RING)
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    str(Fingers.RING)
  File "D:/src/Hacks/PythonEnums/fingers1.py", line 19, in __str__
    return self._display_strings[self.value]
TypeError: 'Fingers' object is not subscriptable

问题似乎是枚举将使用所有类变量作为枚举值,这导致它们返回枚举类型的对象,而不是它们的基础类型。

我能想到的一些解决方法包括:

  1. 将字典称为 Fingers._display_strings.value 。 (然而 Fingers.__display_strings 变成了一个有效的枚举值!)
  2. 使 dict 成为模块变量而不是类变量。
  3. if __str__from_string functions.42-
  4. 与其将 dict 设为类变量,不如定义一个静态方法 _get_display_strings 来返回 dict,因此它不会成为枚举值。

请注意,上面的初始代码和解决方法 1. 使用基础整数值作为字典键。其他选项都要求 dict(或 if 测试)在类本身以外的其他地方定义,因此它必须用类名限定这些值。因此,您只能使用,例如 Fingers.THUMB 获取枚举对象,或 Fingers.THUMB.value 获取基础整数值,而不仅仅是 THUMB 如果使用基础整数值作为字典键,那么您还必须使用它来查找字典,使用例如 [Fingers.THUMB.value] 而不仅仅是 [Fingers.THUMB] 进行索引。

所以,问题是,在保留基础整数值的同时为 Enum 实现字符串映射的最佳或最 Pythonic 方法是什么?

原文由 David Scarlett 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 629
2 个回答

这可以通过 stdlib Enum 完成,但使用 aenum 1更容易:

 from aenum import Enum

class Fingers(Enum):

    _init_ = 'value string'

    THUMB = 1, 'two thumbs'
    INDEX = 2, 'offset location'
    MIDDLE = 3, 'average is not median'
    RING = 4, 'round or finger'
    PINKY = 5, 'wee wee wee'

    def __str__(self):
        return self.string

如果您希望能够通过字符串值进行查找,那么实现新的类方法 _missing_value_ (只是 _missing_ 在 stdlib 中):

 from aenum import Enum

class Fingers(Enum):

    _init_ = 'value string'

    THUMB = 1, 'two thumbs'
    INDEX = 2, 'offset location'
    MIDDLE = 3, 'average is not median'
    RING = 4, 'round or finger'
    PINKY = 5, 'wee wee wee'

    def __str__(self):
        return self.string

    @classmethod
    def _missing_value_(cls, value):
        for member in cls:
            if member.string == value:
                return member


1披露:我是 Python stdlib Enumenum34 backport高级枚举 ( aenum )fec3 库的作者。

原文由 Ethan Furman 发布,翻译遵循 CC BY-SA 3.0 许可协议

也许我错过了这里的重点,但如果你定义

class Fingers(Enum):
    THUMB = 1
    INDEX = 2
    MIDDLE = 3
    RING = 4
    PINKY = 5

然后在 Python 3.6 中你可以做

print (Fingers.THUMB.name.lower())

我认为这就是你想要的。

原文由 BoarGules 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题