Adding members to Python Enums

18,617

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 Enums:

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.

Share:
18,617
Hernan
Author by

Hernan

Updated on June 01, 2022

Comments

  • Hernan
    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
    Hernan over 9 years
    As I mentioned, this is not an option for the exact same reasons that you describe. Thanks anyway
  • Martijn Pieters
    Martijn Pieters over 9 years
    @Hernan: that is your only option when using the enum library, however.
  • likern
    likern almost 7 years
    I get "File "/home/vamalov/.local/lib/python3.5/site-packages/aenum/__in‌​it__.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
    Ethan Furman about 6 years
    @likern, if this is still an issue, please file an issue. Thanks.
  • Gino Mempin
    Gino Mempin over 5 years
    To 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
    Cecil Curry over 5 years
    Immutability 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 mutable aenum.Enum and Java enum types.
  • Martijn Pieters
    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
    Saren Tasciyan over 3 years
    It also turns out to be pickleable.
  • Saren Tasciyan
    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>