Is it possible to have an enum of enums in Python? For example, I\'d like to have
enumA
enumB
elementA
elementB
enumC
elementC
Note The below is interesting, and may be useful, but as @abarnert noted the resulting A Enum doesn't have Enum members -- i.e. list(A) returns an empty list.
Without commenting on whether an Enum of Enums is a good idea (I haven't yet decided ;) , this can be done... and with only a small amount of magic.
You can either use the Constant class from this answer:
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)
Or you can use the new aenum library and its built-in skip desriptor decorator (which is what I will show).
At any rate, by wrapping the subEnum classes in a descriptor they are sheltered from becoming members themselves.
Your example then looks like:
from aenum import Enum, skip
class enumA(Enum):
@skip
class enumB(Enum):
elementA = 'a'
elementB = 'b'
@skip
class enumC(Enum):
elementC = 'c'
elementD = 'd'
and you can then access them as:
print(enumA)
print(enumA.enumB)
print(enumA.enumC.elementD)
which gives you:
enumC.elementD
The difference between using Constant and skip is esoteric: in enumA's __dict__ 'enumB' will return a Constant object (if Constant was used) or if skip was used; normal access will always return .
In Python 3.5+ you can even (un)pickle the nested Enums:
print(pickle.loads(pickle.dumps(enumA.enumC.elementD)) is enumA.enumC.elementD)
# True
Do note that the subEnum doesn't include the parent Enum in it's display; if that's important I would suggest enhancing EnumMeta to recognize the Constant descriptor and modify its contained class' __repr__ -- but I'll leave that as an exercise for the reader. ;)