Why are mutable values in Python Enums the same object? Why are mutable values in Python Enums the same object? python python

Why are mutable values in Python Enums the same object?


From the docs:

Given two members A and B with the same value (and A defined first), B is an alias to A. By-value lookup of the value of A and B will return A. By-name lookup of B will also return A:

>>> class Shape(Enum):...     square = 2...     diamond = 1...     circle = 3...     alias_for_square = 2...>>> Shape.square<Shape.square: 2>>>> Shape.alias_for_square<Shape.square: 2>>>> Shape(2)<Shape.square: 2>

This operates by equality, even when the values are mutable. Since you defined equal values for black and blue, with black first, blue is an alias for black.


To complement @user2357112's answer, take a look in EnumMeta, the metaclass for all Enum 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:

    # If another member with the same value was already defined, the    # new member becomes an alias to the existing one.    for name, canonical_member in enum_class._member_map_.items():        if canonical_member._value_ == enum_member._value_:            enum_member = canonical_member            break

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:

By default, enumerations allow multiple names as aliases for the same value. When this behavior isn’t desired, the following decorator can be used to ensure each value is used only once in the enumeration....

This means that blue is an alias for black. 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 enum import Enum, unique>>> @unique ... class Mistake(Enum): ...     one = 1 ...     two = 2 ...     three = 3 ...     four = 3 ... Traceback (most recent call last): ... ValueError: duplicate values found in <enum 'Mistake'>: four -> three