我试图创建一个具有整数值的枚举,但它也可以 for each 值返回一个显示友好的字符串.我想我可以定义一个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. __str__from_string函数中复制dict(可能还会将其分解为一系列if个语句).
  4. 与其让dict成为类变量,不如定义一个静态方法_get_display_strings来返回dict,这样它就不会变成枚举值.

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

所以,问题是,在保留基础整数值的同时,实现枚举的字符串映射的最佳或最具python风格的方法是什么?

推荐答案

这可以通过stdlib Enum实现,但使用aenum1要容易得多:

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_(stdlib中只有_missing_):

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 backportAdvanced Enumeration (aenum)图书馆的作者.

Python-3.x相关问答推荐

IPython似乎已安装但无法运行

使用具有相同索引的多次出现的索引列表更新NumPy数组

从.csv导入将文件夹路径加入到文件名

无法使用Python发送带有参数和标头的POST请求

将两列的乘积连续添加到一列的累积和中

为什么空列表也能起作用?

无法理解此递归函数的分配和环境用法

仅当从 USB 摄像头接收到新图像时才处理图像

Python 3 - 给定未知数量的类别动态地将字典嵌套到列表中

Python Regex 查找给定字符串是否遵循交替元音、辅音或辅音、元音的连续模式

包含值超出范围的 ID 的新 DataFrame 列?

在字符串中查找正则表达式的所有模式

段落中句子的索引

使用一周的特定第一天将每日日期转换为每周

参数化泛型不能与类或实例判断一起使用

Python - 使用 OpenCV 将字节图像转换为 NumPy 数组

ValueError:找不到子字符串,我做错了什么?

pandas 中 df.reindex() 和 df.set_index() 方法的区别

如何使用python将放置在多个嵌套文件夹中的文档移动和重命名为一个新的单个文件夹?

我可以替换 Python 中对象的现有方法吗?