Python中枚举的枚举?

Python中枚举的枚举?,python,python-3.x,enums,Python,Python 3.x,Enums,在Python中可以有一个枚举吗?例如,我想 enumA enumB elementA elementB enumC elementC elementD 我可以将elementA称为enumA.enumB.elementA,或者将elementD称为enumA.enumC.elementD 这可能吗?如果是,怎么做 编辑:以朴素的方式实现时: from enum import Enum class EnumA(E

在Python中可以有一个枚举吗?例如,我想

enumA
    enumB
        elementA
        elementB
    enumC
        elementC
        elementD
我可以将
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)
它给出:

<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'

回溯(最近一次呼叫最后一次):
文件“Maps.py”,第15行,在
打印(EnumA.EnumB.member)
AttributeError:'EnumA'对象没有属性'member'

您可以使用namedtuples执行以下操作:

>>> from collections import namedtuple
>>> Foo = namedtuple('Foo', ['bar', 'barz'])
>>> Bar = namedtuple('Bar', ['element_a', 'element_b'])
>>> Barz = namedtuple('Barz', ['element_c', 'element_d'])
>>> bar = Bar('a', 'b')
>>> barz = Barz('c', 'd')
>>> foo = Foo(bar, barz)
>>> foo
Foo(bar=Bar(element_a='a', element_b='b'), barz=Barz(element_c='c', element_d='d'))
>>> foo.bar.element_a
'a'
>>> foo.barz.element_d
'd'

这不是枚举,但可能解决了您的问题

您不能使用
enum
stdlib模块来实现这一点。如果您尝试:

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

A.B.a
…您将得到一个异常,如:

AttributeError: 'A' object has no attribute 'a'
这是因为
A
的枚举值与
A
的实例类似,而与其值类型的实例不同。就像持有
int
值的普通枚举在值上没有
int
方法一样,
B
也不会有
enum
方法。比较:

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

D.a.bit_length()

当然,您可以显式地访问基础值(
int
,或
B
类):

D.a.value.bit_length()
A.B.value.a
…但我怀疑这是你想要的


那么,您是否可以使用
IntEnum
使用的相同技巧,对
Enum
int
进行子类化,使其枚举值为
int
值,如文档部分所述

不,因为您将子类化什么类型?不
枚举
;那已经是你喜欢的类型了。不能使用
类型
(任意类的类型)。没有什么是有效的

因此,您必须使用具有不同设计的不同Enum实现来实现这一点。幸运的是,在PyPI和ActiveState上有大约69105个不同的选项可供选择


例如,当我考虑构建类似于Swift枚举(比Python/Java/等枚举更接近ML-adt)的东西时,有人推荐我看一下。我忘了这么做,但现在我只是这么做了,而且:

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)
这将为您提供:

<Object: B -> [a:0, b:1]> <Value: B.b = 1> b 1
<enum 'enumA'>
<enum 'enumB'>
enumC.elementD
[a:0,b:1]>b1

如果它查看其创建str/repr值的
\uuuuu qualname\uuuu
而不是
\uuuu name\uuuuuuuu
,这可能会很好,但在其他方面,它看起来好像做了您想要的一切。它还有其他一些很酷的功能(不完全是我想要的,但很有趣…。

注意,下面的内容很有趣,可能很有用,但正如@abarnert所指出的,生成的
A
Enum没有
Enum
成员,即
list(A)
返回一个空列表


不必评论枚举的枚举是否是一个好主意(我还没有决定;),这可以做到。。。而且只有少量的魔法

您可以从以下位置使用
常量
类:

或者您可以使用新库及其内置的
skip
desriptor装饰器(我将展示)

无论如何,通过将子枚举类包装在描述符中,可以避免它们自己成为成员

您的示例如下所示:

from aenum import Enum, skip

class enumA(Enum):
    @skip
    class enumB(Enum):
        elementA = 'a'
        elementB = 'b'
    @skip
    class enumC(Enum):
        elementC = 'c'
        elementD = 'd'
然后,您可以通过以下方式访问它们:

print(enumA)
print(enumA.enumB)
print(enumA.enumC.elementD)
这给了你:

<Object: B -> [a:0, b:1]> <Value: B.b = 1> b 1
<enum 'enumA'>
<enum 'enumB'>
enumC.elementD

请注意,子枚举在其显示中不包括父枚举;如果这很重要,我建议增强
EnumMeta
以识别
常量
描述符,并修改其包含的类“
\uuuuu repr\uuuu
”——但我将把它留给读者作为练习

我在基本枚举中创建了一个实现de _uuugetattr uuu的枚举,如下所示

def __getattr__(self, item):
    if item != '_value_':
        return getattr(self.value, item).value
    raise AttributeError
在我的例子中,我有一个enum of enum of enum

class enumBase(Enum):
    class innerEnum(Enum):
        class innerInnerEnum(Enum):
           A


基于ATTR的有效解决方案。这还允许实现属性验证器和属性的其他优点:

import enum

import attr


class CoilsTypes(enum.Enum):
    heating: str = "heating"


class FansTypes(enum.Enum):
    plug: str = "plug"


class HrsTypes(enum.Enum):
    plate: str = "plate"
    rotory_wheel: str = "rotory wheel"


class FiltersTypes(enum.Enum):
    bag: str = "bag"
    pleated: str = "pleated"


@attr.dataclass(frozen=True)
class ComponentTypes:
    coils: CoilsTypes = CoilsTypes
    fans: FansTypes = FansTypes
    hrs: HrsTypes = HrsTypes
    filter: FiltersTypes = FiltersTypes


cmp = ComponentTypes()
res = cmp.hrs.plate

首先,您必须使用stdlib
enum
模块或第三方模块,以Python语法编写此代码。那么…你试过了吗?发生了什么?我很好奇-为什么您首先需要这个功能?具体的用例是什么?@inspectorG4dget我想在我的RPG引擎的通用对象系统中提供一个对象分类系统。例如,可以将对象分类为terrain.rocks.smallRock或武器、近战、剑、短剑。有更好的方法吗?看起来应该是动态信息,而不是静态信息——换句话说,是存储在字符串或元组中的信息,而不是作为类型的一部分。除非这是为了用于嵌入式Python控制台或其他什么东西?对象引擎中的对象类型是不可变的——尽管我现在正在重新考虑这一点。谢谢。现在这就更有意义了。你建议我怎么做?请参阅我在OP上的评论。@silverwingdseraph:正如我在最后所说的,我将首先查看所有其他enum实现的PyPI和ActiveState,看看其中是否有一个设计更接近您想要的。你所要求的似乎是合理的,只是不是stdlib所采用的设计,所以很有可能其他人也这么做了。谢谢。现在我决定采用一种不同的系统,但我会在某个时候回到这个问题上来,看看那些。事实上,这是可以做到的。请注意,我并不是说这是个好主意。如果你好奇,请检查我的答案。@furman好吧,你的答案实际上没有
Enum
值,它有
常量
值。当然,您使用的是
Enum
类型来定义那些
Constant
实例,所以看起来您一直在使用Enum。我认为这可能是误导性的,而不是帮助性的,但答案是值得的——任何读过它并了解它是如何工作的人都会学到一些有用的东西,如果没有其他东西的话。谢谢。虽然这不能解决我的问题,但知道这一点非常有用+这对我来说是最好的答案,因为我有一个巨大的身躯
import enum

import attr


class CoilsTypes(enum.Enum):
    heating: str = "heating"


class FansTypes(enum.Enum):
    plug: str = "plug"


class HrsTypes(enum.Enum):
    plate: str = "plate"
    rotory_wheel: str = "rotory wheel"


class FiltersTypes(enum.Enum):
    bag: str = "bag"
    pleated: str = "pleated"


@attr.dataclass(frozen=True)
class ComponentTypes:
    coils: CoilsTypes = CoilsTypes
    fans: FansTypes = FansTypes
    hrs: HrsTypes = HrsTypes
    filter: FiltersTypes = FiltersTypes


cmp = ComponentTypes()
res = cmp.hrs.plate