在 Python 中为 Enum 类创建属性

All*_*mon 2 python enums class python-3.x

我必须在枚举中创建额外的映射来保存附加信息,例如每个枚举案例的详细描述,但又不会丢失枚举类属性。前任:

class MyEnumBase:
    description = {
        1: 'Description 1',
        2: 'This is anover description',
        3: 'la la la',
    }

class MyEnum(MyEnumBase, Enum):
    First = 1
    Second = 2
    Third = 3
Run Code Online (Sandbox Code Playgroud)

所以我像这样访问它 MyEnum.description[3] == 'la la la'

如何扩展 Enum 类,以便在描述与枚举名称相同的情况下,它会使用字段名称填充此字典?

例如:

class MyAnotherEnum(CustomEnumBase):
    aaa = 1
    bbb = 2
    ccc = 3
Run Code Online (Sandbox Code Playgroud)

这样,就会为由此创建的每个枚举MyAnotherEnum.description[3] == 'ccc'自动生成属性。descriptionCustomEnumBase

我试图延长Enum课程时间,但我尝试过的所有方法都失败了。我在想这样的事情:

class CustomEnumBase:
    @property
    def names(cls):
        return {
            id:member.name
            for id, member in cls._value2member_map_.items()
        }
Run Code Online (Sandbox Code Playgroud)

有 2 个限制:

  1. 它应该扩展 python Enum 类,因此在需要 Enum 的地方它的行为正确。有一些第三方代码依赖于此。

  2. 它应该保留对描述作为映射的访问,因为该协议已经被预期并在代码库中使用。因此将其更改为MyAnotherEnum.description()[id]不可行,因为它期望映射(字典),而不是函数。

Eth*_*man 5

If you are using Python 3.6+ the stdlib Enum will do; otherwise, you'll need to use the aenum1 library. In both cases you'll need a to create your own _generate_next_value_ method:

def _generate_next_value_(name, start, count, last_values):
    return start+count, name
Run Code Online (Sandbox Code Playgroud)
  • name is the name of the member
  • start is the start value for the enumeration (defaults to 1)
  • count is the number of members so far
  • last_values is a list of the member values so far

and borrow classproperty from this answer:

class classproperty:

    def __init__(self, func):
        self._func = func

    def __get__(self, obj, owner):
        return self._func(owner)
Run Code Online (Sandbox Code Playgroud)

If using aenum (my favorite), the base class will look like:

from aenum import Enum, auto

class DescriptionEnum(Enum):
    _init_ = 'value description'

    @staticmethod
    def _generate_next_value_(name, start, count, last_values):
        return start+count, name

    @classproperty
    def description(cls):
        return {
            e.value: e.description
            for e in cls
            }
    print(description)
Run Code Online (Sandbox Code Playgroud)

If using Python 3.6 and the stdlib Enum the base class will look like:

from enum import Enum, auto

class DescriptionEnum(Enum):

    def __new__(cls, value, description):
        obj = object.__new__(cls)
        obj._value_ = value
        obj.description = description
        return obj

    def _generate_next_value_(name, start, count, last_values):
        print('generating value', start+count, name)
        return start+count, name

    @classproperty
    def description(cls):
        return {
            e.value: e.description
            for e in cls
            }
Run Code Online (Sandbox Code Playgroud)

The difference between those two base classes is the _init_ line vs. the __new__ method. In both cases, your final class would be:

class MyAnotherEnum(DescriptionEnum):
    aaa = auto()
    bbb = auto()
    ccc = auto()
Run Code Online (Sandbox Code Playgroud)

and in use:

>>> print(list(MyAnotherEnum))
    [<MyAnotherEnum.aaa: 1>, <MyAnotherEnum.bbb: 2>, <MyAnotherEnum.ccc: 3>]

>>> print(MyAnotherEnum.bbb)
    MyAnotherEnum.bbb

>>> print(MyAnotherEnum.bbb.description)
    bbb

>>> print(MyAnotherEnum.description)
    {1: 'aaa', 2: 'bbb', 3: 'ccc'}

>>> print(MyAnotherEnum.description[2])
    bbb
Run Code Online (Sandbox Code Playgroud)

虽然你的Enums 没有,但这个新成员description为每个成员以及Enum整个成员都有一个属性。这样做的优点之一是,您可以对名称为描述的枚举和指定描述的枚举使用相同的基类:

class MyNormalEnum(DescriptionEnum):
    aaa = 1, 'howdy'
    bbb = 2, 'bye'
    ccc = 3, 'whatever'
Run Code Online (Sandbox Code Playgroud)

并在使用中:

>>> print(list(MyNormalEnum))
    [<MyNormalEnum.aaa: 1>, <MyNormalEnum.bbb: 2>, <MyNormalEnum.ccc: 3>]

>>> print(MyNormalEnum.bbb)
    MyNormalEnum.bbb

>>> print(MyNormalEnum.bbb.description)
    bye

>>> print(MyNormalEnum.description)
    {1: 'howdy', 2: 'bye', 3: 'whatever'}

>>> print(MyNormalEnum.description[2])
    bye
Run Code Online (Sandbox Code Playgroud)

1声明:我是Python stdlibEnumenum34backportAdvanced Enumeration ( aenum)库的作者 。