Adding members to Python Enums
Solution 1
Enums are immutable, that's rather the point. You can create a new enum that replaces the original instead:
from enum import Enum
names = [m.name for m in ExistingEnum] + ['newname1', 'newname2']
ExistingEnum = Enum('ExistingEnum', names)
but any existing references (say, in other modules) would continue to use the old definition.
names
can be:
- A string containing member names, separated either with spaces or commas. Values are incremented by 1 from
start
(which can be set as a keyword argument and defaults to 1). - An iterable of member names (as in the code above). Values are incremented by 1 from
start
. - An iterable of (member name, value) pairs.
- A mapping of member name -> value pairs.
Solution 2
This is a job for the extend_enum
function from the aenum library1.
A couple sample Enum
s:
from aenum import Enum
class Color(Enum):
black = 0
class ColorHelp(Enum):
_init_ = 'value __doc__'
black = 0, 'the absence of color'
extend_enum
in action:
from aenum import extend_enum
extend_enum(Color, 'white', 1)
print Color, list(Color)
print repr(Color.black), Color.black, repr(Color.white), Color.white
print
extend_enum(ColorHelp, 'white', 1, 'the presence of every color')
print ColorHelp, list(ColorHelp)
print repr(ColorHelp.black), ColorHelp.black, ColorHelp.black.__doc__, repr(ColorHelp.white), ColorHelp.white, ColorHelp.white.__doc__
Which gives us:
<enum 'Color'> [<Color.black: 0>, <Color.white: 1>]
<Color.black: 0> Color.black <Color.white: 1> Color.white
<enum 'ColorHelp'> [<ColorHelp.black: 0>, <ColorHelp.white: 1>]
<ColorHelp.black: 0> ColorHelp.black the absence of color <ColorHelp.white: (1, 'the presence of every color')> ColorHelp.white None
1 Disclosure: I am the author of the Python stdlib Enum
, the enum34
backport, and the Advanced Enumeration (aenum
) library.
Hernan
Updated on June 01, 2022Comments
-
Hernan about 2 years
I understand that this is NOT the standard use case, but I need to dynamically add elements to a
IntEnum
derived class in Python. Notice that dynamically creating the Enum using the functional API is not enough. I need to add elements to an existing enum. How can I do this?Background: For those of you wondering why would somebody want to do this. I am wrapping a library and the values for the enum are defined within the library. I can query the names and values using the library API. But I cannot do it upon initialization as it depends on components which are dynamically loaded by the library upon user request. I could load all components at start up and use the functional API to create the enum upon import but this is time consuming and has side effects.
-
Hernan over 9 yearsAs I mentioned, this is not an option for the exact same reasons that you describe. Thanks anyway
-
Martijn Pieters over 9 years@Hernan: that is your only option when using the
enum
library, however. -
likern almost 7 yearsI get "File "/home/vamalov/.local/lib/python3.5/site-packages/aenum/__init__.py", line 2166, in extend_enum for canonical_value in canonical_member._values_: AttributeError: 'MachineName' object has no attribute 'values'", where MachineName is usual python enum. Is this method still working?
-
Ethan Furman about 6 years@likern, if this is still an issue, please file an issue. Thanks.
-
Gino Mempin over 5 yearsTo anyone coming here who is having the same error as @likern, make sure to use aenum's Enum (
from aenum import Enum
) instead of the regular Enum (from enum import Enum
). -
Cecil Curry over 5 yearsImmutability is not "the point" of enumerations. Enumerations exist to guarantee mutual exclusion over a finite unordered set. Appending additional members onto an existing enumeration at runtime in no way violates this guarantee. That Python's standard
enum.Enum
type chose to prohibit this valid use case in no way prohibits third-party alternatives from doing so. See also: the mutableaenum.Enum
and Javaenum
types. -
Martijn Pieters over 5 years@CecilCurry: Neither of those libraries mutate the original enum, they extend on an existing enum to create a new enum. If enums were mutable at runtime, that'd have a wide range of implications where you can no longer guarantee to be handling all possible values (languages like Rust even build their type safety on enums not being runtime mutable).
-
Saren Tasciyan over 3 yearsIt also turns out to be pickleable.
-
Saren Tasciyan over 3 years@EthanFurman I would like to correct my previous comment. I could not load the pickle object with extended enum. Default enum definition doesn't include some of the items. ValueError: <enumValue> is not a valid <EnumType>