Python Enum 组合

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

我想基于两个现有的 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)])))

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

@unique
class CombinedEnumClass(IntEnum):
    """ docstring """
    # magic needed here

有什么想法吗?谢谢!

python enums metaprogramming python-3.5 metaclass
3个回答
8
投票

Python 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))

这之所以有效,是因为:

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

我们删除

member
cls
,因为我们不希望他们成为会员。


Python 3

以上内容(尚)不适用于 Python3 3.4 和 3.5 中的新

Enum
(不确定 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

1 披露:我是 Python stdlib

Enum
enum34
向后移植
高级枚举 (
aenum
)
库的作者。


1
投票

图书馆明确阻止这样做:

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

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

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


0
投票

我需要连接多个枚举,最后我得到了这个,(使用Stackoverflow答案解决)

from enum import Enum, IntFlag

def extend_flag(inherited,type):
   def wrapper(final):
     joined = {}
     inherited.append(final)
     for i in inherited:
        c=[j for j in i]
        for j in i:
           joined[j.name] = j.value
     return _type(final.__name__, joined)
   return wrapper

当与 Enum 一起使用时,它工作得很好,但与 IntFlag 一起使用时则不然。无法解释为什么。

class A(Enum):
   a = "one"
   b = "two"

class B(Enum):
   c = "three"
   d = "four"


@extend_flag([A,B], Enum)
class C(Enum):
   e = "five"

print(C('three'))
print(C.b)
© www.soinside.com 2019 - 2024. All rights reserved.