While experimenting with different value types for Enum
members, I discovered some odd behavior when the values are mutable.
If I define the values of an Enum
as different lists, the members still behave similarly to when the Enum
values are typical immutable types like str
or int
, even though I can change the values of the members in place so that the values of the two Enum
members are the same:
>>> class Color(enum.Enum):
black = [1,2]
blue = [1,2,3]
>>> Color.blue is Color.black
False
>>> Color.black == Color.blue
False
>>> Color.black.value.append(3)
>>> Color.black
<Color.black: [1, 2, 3]>
>>> Color.blue
<Color.blue: [1, 2, 3]>
>>> Color.blue == Color.black
False
>>> Color.black.value == Color.blue.value
True
However, if I define the values to be identical lists, each member's value seems to be the same object, and thus any mutation of one member's value affects all members:
>>> class Color(enum.Enum):
black = [1,2,3]
blue = [1,2,3]
>>> Color.blue is Color.black
True
>>> Color.black == Color.blue
True
>>> Color.black.value.append(4)
>>> Color.black
<Color.black: [1, 2, 3, 4]>
>>> Color.blue
<Color.black: [1, 2, 3, 4]>
>>> Color.blue == Color.black
True
Why does Enum
behave this way? Is it the intended behavior or is it a bug?
NOTE: I'm not planning on actually using Enums this way, I was simply experimenting with using non-standard values for Enum members
To complement @user2357112's answer, take a look in
EnumMeta
, the metaclass for allEnum
classes; it gets a peek at every class definition that has its type and gets a change to alter it.Specifically, it takes care to re-assign members with the same value in its
__new__
method via simple assignment:I didn't opt to check the docs and instead looked in the source. Lesson to take: Always check the docs, and if
ExplanationNotFound
is raised; check the source :-)From the Python documentation for Enums:
This means that
blue
is an alias forblack
. When either one changes, the other must as well.You can however, force Python to make each enum value unique, by using the
enum.unique
decorator. Also from the docs:From the docs:
This operates by equality, even when the values are mutable. Since you defined equal values for
black
andblue
, withblack
first,blue
is an alias forblack
.Python 3 Enum class doesn't enforce uniqueness unless you specifically tell it to via the unique decorator
See also duplicate values. since
blue
is identical toblack
, it just becomes an alias forblack
.