Yes there is, and it's my favorite recipe so far. As a bonus, one does not have to specify the integer value either. Here's an example:
class AddressSegment(AutoEnum):
misc = "not currently tracked"
ordinal = "N S E W NE NW SE SW"
secondary = "apt bldg floor etc"
street = "st ave blvd etc"
You might ask why I don't just have "N S E W NE NW SE SW"
be the value of ordinal
? Because when I get its repr seeing <AddressSegment.ordinal: 'N S E W NE NW SE SW'>
gets a bit clunky, but having that information readily available in the docstring is a good compromise.
Here's the recipe for the Enum:
class AutoEnum(enum.Enum):
"""
Automatically numbers enum members starting from 1.
Includes support for a custom docstring per member.
"""
#
def __new__(cls, *args):
"""Ignores arguments (will be handled in __init__."""
value = len(cls) + 1
obj = object.__new__(cls)
obj._value_ = value
return obj
#
def __init__(self, *args):
"""Can handle 0 or 1 argument; more requires a custom __init__.
0 = auto-number w/o docstring
1 = auto-number w/ docstring
2+ = needs custom __init__
"""
if len(args) == 1 and isinstance(args[0], (str, unicode)):
self.__doc__ = args[0]
elif args:
raise TypeError('%s not dealt with -- need custom __init__' % (args,))
And in use:
>>> list(AddressSegment)
[<AddressSegment.ordinal: 1>, <AddressSegment.secondary: 2>, <AddressSegment.misc: 3>, <AddressSegment.street: 4>]
>>> AddressSegment.secondary
<AddressSegment.secondary: 2>
>>> AddressSegment.secondary.__doc__
'apt bldg floor etc'
The reason I handle the arguments in __init__
instead of in __new__
is to make subclassing AutoEnum
easier should I want to extend it further.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…