Python 枚举组合

was*_*zil 7 python enums metaprogramming metaclass python-3.5

我想基于两个现有的 Enum (IntEnum) 类创建一个新的 Enum (IntEnum) 类。有一个可行的解决方案,如下所示:

from enum import unique, IntEnum
from itertools import chain
from collections import OrderedDict

@unique
class FirstEnumClass(IntEnum):
    a = 1
    b = 2

@unique
class SecondEnumClass(IntEnum):
    c = 3
    d = 4

# here a combined class is created:
CombinedEnumClass = unique(IntEnum('CombinedEnumClass', OrderedDict([(i.name, i.value) for i in chain(FirstEnumClass, SecondEnumClass)])))
Run Code Online (Sandbox Code Playgroud)

我的问题:有没有一种奇特的方法来实现这一点,以便有一个正确的类定义?就像重写一些元类方法一样?我想要这样的东西,这样也可以给出文档字符串:

@unique
class CombinedEnumClass(IntEnum):
    """ docstring """
    # magic needed here
Run Code Online (Sandbox Code Playgroud)

任何想法?谢谢!

Eth*_*man 6

蟒蛇2

使用一个技巧vars()可以实现这一点:

class CombinedEnum(IntEnum):
    """ doc string """
    cls = vars()
    for member in chain(list(FirstEnumClass), list(SecondEnumClass)):
        cls[member.name] = member.value
    del member, cls

print(list(CombinedEnum))
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为:

  • vars()返回当前命名空间
  • 修改该命名空间会修改该类

我们删除member和 是cls因为我们不希望他们成为会员。


蟒蛇3

上面的内容(还)不适用于EnumPython3 3.4 和 3.5 中的新功能(不确定 3.6)。解决方法是使用aenum替代方法,它允许我们告诉Enum忽略某些名称:

from aenum import IntEnum

class CombinedEnum(IntEnum):
    """ doc string """
    _ignore_ = 'member cls'
    cls = vars()
    for member in chain(list(FirstEnumClass), list(SecondEnumClass)):
        cls[member.name] = member.value
Run Code Online (Sandbox Code Playgroud)

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


Kru*_*pös 0

该库明确阻止这样做:

仅当枚举未定义任何成员时才允许对枚举进行子类化。

允许对定义成员的枚举进行子类化将导致违反类型和实例的一些重要不变量。另一方面,允许在一组枚举之间共享一些共同行为是有意义的。

因此,我找到了一个Stackoverflow 答案,使用与您几乎相同的解决方法。我认为这是唯一的办法。