Python中的枚举枚举?

Leo*_*all 6 python enums python-3.x

是否可以在Python中使用enum枚举?例如,我想拥有

enumA
    enumB
        elementA
        elementB
    enumC
        elementC
        elementD
Run Code Online (Sandbox Code Playgroud)

并且对我来说可以elementA称为enumA.enumB.elementA,或elementD称为enumA.enumC.elementD.

这可能吗?如果是这样,怎么样?

编辑:以天真的方式实施:

from enum import Enum

class EnumA(Enum):
    class EnumB(Enum):
        member = 0

print(EnumA)
print(EnumA.EnumB.member)
Run Code Online (Sandbox Code Playgroud)

它给:

<enum 'EnumA'>
Traceback (most recent call last):
  File "Maps.py", line 15, in <module>
    print(EnumA.EnumB.member)
AttributeError: 'EnumA' object has no attribute 'member'
Run Code Online (Sandbox Code Playgroud)

aba*_*ert 8

您无法使用enumstdlib模块执行此操作.如果你试试:

class A(Enum):
    class B(Enum):
        a = 1
        b = 2
    class C(Enum):
        c = 1
        d = 2

A.B.a
Run Code Online (Sandbox Code Playgroud)

...你会得到一个例外:

AttributeError: 'A' object has no attribute 'a'
Run Code Online (Sandbox Code Playgroud)

这是因为枚举值的A行为类似于实例A,而不像它们的值类型的实例.就像正常的枚举持有int值没有值的int方法一样,B也没有Enum方法.相比:

class D(Enum):
    a = 1
    b = 2

D.a.bit_length()
Run Code Online (Sandbox Code Playgroud)

当然,您可以显式访问基础值(intB类):

D.a.value.bit_length()
A.B.value.a
Run Code Online (Sandbox Code Playgroud)

......但我怀疑这就是你想要的.


所以,你可以使用同样的伎俩IntEnum使用,继承两者Enumint使其枚举值 int值,如所描述的其他的文档的部分?

不,因为你将什么类型的子类?没有Enum; 这已经是你的类型了.你不能使用type(任意类的类型).什么都行不通.

因此,您必须使用具有不同设计的不同Enum实现来实现此功能.幸运的是,PyPI和ActiveState上有大约69105个不同的可供选择.


例如,当我在构建类似于Swift枚举的东西时(比ML/Java/Java等枚举更接近ML ADT),有人推荐我看一下makeobj.我忘了这样做,但现在我做了,并且:

class A(makeobj.Obj):
    class B(makeobj.Obj):
        a, b = makeobj.keys(2)
    class C(makeobj.Obj):
        c, d = makeobj.keys(2)

print(A.B, A.B.b, A.B.b.name, A.B.b.value)
Run Code Online (Sandbox Code Playgroud)

这给你:

<Object: B -> [a:0, b:1]> <Value: B.b = 1> b 1
Run Code Online (Sandbox Code Playgroud)

它可能很好看,__qualname__而不是它__name__用于创建str/repr值,但否则看起来它会做你想要的一切.它还有其他很酷的功能(不完全是我想要的,但很有趣......).


Eth*_*man 5

注意 以下内容很有意思,可能有用,但是正如@abarnert指出的那样,结果AEnum没有Enum成员-即list(A)返回一个空列表。


无需评论枚举是否是一个好主意(我尚未决定;),只需少量的魔术就可以完成。

您可以使用以下答案中Constant类:

class Constant:
    def __init__(self, value):
        self.value = value
    def __get__(self, *args):
        return self.value
    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, self.value)
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用新的aenum库及其内置的skipdesriptor装饰器(这就是我将要显示的内容)。

无论如何,通过将subEnum类包装在描述符中,可以避免它们成为成员本身。

您的示例如下所示:

from aenum import Enum, skip

class enumA(Enum):
    @skip
    class enumB(Enum):
        elementA = 'a'
        elementB = 'b'
    @skip
    class enumC(Enum):
        elementC = 'c'
        elementD = 'd'
Run Code Online (Sandbox Code Playgroud)

然后您可以通过以下方式访问它们:

print(enumA)
print(enumA.enumB)
print(enumA.enumC.elementD)
Run Code Online (Sandbox Code Playgroud)

这给你:

<enum 'enumA'>
<enum 'enumB'>
enumC.elementD
Run Code Online (Sandbox Code Playgroud)

使用之间的差Constantskip是深奥:在enumA__dict__ 'enumB'将返回一个Constant对象(如果Constant使用),或者<enum 'enumB'>如果skip使用了; 正常访问将始终返回<enum 'enumB'>

在Python 3.5+中,您甚至可以(取消)嵌套的枚举:

print(pickle.loads(pickle.dumps(enumA.enumC.elementD)) is enumA.enumC.elementD)
# True
Run Code Online (Sandbox Code Playgroud)

请注意,subEnum的显示中不包含父Enum;如果那很重要,我建议您增强EnumMeta以识别Constant描述符并修改其包含的类' __repr__-但我将其留给读者练习。;)


Hei*_*oro 5

我制作了一个 enum 的 enum 在基本 enum 中实现 de __ getattr __ 这样

def __getattr__(self, item):
    if item != '_value_':
        return getattr(self.value, item).value
    raise AttributeError
Run Code Online (Sandbox Code Playgroud)

就我而言,我有一个 enum of enum

class enumBase(Enum):
    class innerEnum(Enum):
        class innerInnerEnum(Enum):
           A
Run Code Online (Sandbox Code Playgroud)

enumBase.innerEnum.innerInnerEnum.A
Run Code Online (Sandbox Code Playgroud)

作品

  • 这对我来说是最好的答案,作为一个拥有庞大图书馆并依赖于枚举的人,很难改变到一个全新的图书馆。还有 ```return getattr(self.value, item).value``` 如果改为 ```return getattr(self.value, item)``` 会很棒!值可通过枚举访问,因此设计保持不变。 (3认同)