Enum of enums in Python?
是否可以在python中使用枚举?例如,我想
1 2 3 4 5 6 7 | enumA enumB elementA elementB enumC elementC elementD |
我可以把
这有可能吗?如果是这样,怎么办?
编辑:以幼稚的方式实现时:
1 2 3 4 5 6 7 8 | from enum import Enum class EnumA(Enum): class EnumB(Enum): member = 0 print(EnumA) print(EnumA.EnumB.member) |
它给出:
1 2 3 4 5 | <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' |
您不能使用
1 2 3 4 5 6 7 8 9 | class A(Enum): class B(Enum): a = 1 b = 2 class C(Enum): c = 1 d = 2 A.B.a |
…你会得到一个例外,比如:
1 | AttributeError: 'A' object has no attribute 'a' |
这是因为
1 2 3 4 5 | class D(Enum): a = 1 b = 2 D.a.bit_length() |
当然,您可以显式访问基础值(
1 2 | D.a.value.bit_length() A.B.value.a |
…但我怀疑这就是你想要的。
那么,您是否可以使用与
不,因为您要子类化什么类型?不是
因此,您必须使用具有不同设计的不同枚举实现来实现这一点。幸运的是,Pypi和ActiveState上有大约69105个不同的选项可供选择。
例如,当我在寻找类似SWIFT枚举(比Python/Java/枚举)更接近ML的ADT时,有人推荐我看EDCOX1(15)。我忘了这样做,但现在我刚刚做了,而且:
1 2 3 4 5 6 7 | 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) |
这给了你:
1 | <Object: B -> [a:0, b:1]> <Value: B.b = 1> b 1 |
如果它在创建str/repr值时查看它的
注意下面的内容很有趣,可能有用,但是正如@abarnett所指出的那样,生成的
在不评论枚举是否是一个好主意的情况下(我还没有决定;),这可以做到…只有少量的魔法。
您可以使用此答案中的
1 2 3 4 5 6 7 | 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) |
或者您可以使用新的aenum库及其内置的
无论如何,通过将子枚举类包装在描述符中,可以避免它们自己成为成员。
您的示例如下:
1 2 3 4 5 6 7 8 9 10 11 | from aenum import Enum, skip class enumA(Enum): @skip class enumB(Enum): elementA = 'a' elementB = 'b' @skip class enumC(Enum): elementC = 'c' elementD = 'd' |
然后您可以访问它们:
1 2 3 | print(enumA) print(enumA.enumB) print(enumA.enumC.elementD) |
这给了你:
1 2 3 | <enum 'enumA'> <enum 'enumB'> enumC.elementD |
使用
在python 3.5+中,甚至可以(取消)pickle嵌套的枚举:
1 2 | print(pickle.loads(pickle.dumps(enumA.enumC.elementD)) is enumA.enumC.elementD) # True |
请注意,子枚举在其显示中不包括父枚举;如果这很重要,我建议增强
我做了一个枚举,在基枚举中实现de_uuuugetattr,如下所示
1 2 3 4 | def __getattr__(self, item): if item != '_value_': return getattr(self.value, item).value raise AttributeError |
在我的例子中,我有一个枚举枚举
1 2 3 4 | class enumBase(Enum): class innerEnum(Enum): class innerInnerEnum(Enum): A |
和
1 | enumBase.innerEnum.innerInnerEnum.A |
作品
可以使用NamedDuples执行以下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> 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' |
这不是枚举,但可以解决您的问题
基于ATTR的解决方案。这还允许实现属性验证器和ATTR的其他优点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @attr.s(frozen=True, auto_attribs=True) class Cntfl: upper: str = attr.ib(default="upper") bottom: str = attr.ib(default="bottom") @attr.s(frozen=True, auto_attribs=True) class Phex: cntfl: Cntfl = attr.ib(default=Cntfl()) crsfl: Cntfl = attr.ib(default=Cntfl()) @attr.s(frozen=True, auto_attribs=True) class Comp: phex: Phex = attr.ib(default=Phex()) Comp = Comp() c = Comp.phex.cntfl.bottom print(c) # -> bottom |