Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are mutable values allowed in Python Enums?

This is somewhat of a follow on to Why are mutable values in Python Enums the same object?.

If the values of an Enum are mutable (e.g. lists, etc.), those values can be changed at any time. I think this poses something of an issue if Enum members are retrieved by value, especially if someone inadvertently changes the value of an Enum he looks up:

>>> from enum import Enum
>>> class Color(Enum):
        black = [1,2]
        blue = [1,2,3]

>>> val_1 = [1,2]
>>> val_2 = [1,2,3]

>>> Color(val_1)
<Color.black: [1, 2]>

>>> Color(val_2)
<Color.blue: [1, 2, 3]>

>>> my_color = Color(val_1)
>>> my_color.value.append(3)

>>> Color(val_2)
<Color.black: [1, 2, 3]>

>>> Color(val_1)
Traceback (most recent call last):
  ...
ValueError: [1, 2] is not a valid Color

I think given normal Python idioms this is okay, with the implication being that users can use mutables as their Enum values, but just to understand the can of worms they might be opening.

However this brings up a second issue - since you can look up an Enum memeber by value, and the value can be mutable, it must be doing the lookup by a means other than a hashmap/dict, since the mutable cannot be a key in such a dict.

Wouldn't it be more efficient (although, granted, less flexible) to limit Enum values to only immutable types so that lookup-by-value could be implemented with a dict?

like image 647
Billy Avatar asked Nov 17 '16 14:11

Billy


People also ask

Are enums mutable in Python?

Enumerations are immutable It means you cannot add or remove members once an enumeration is defined. And you also cannot change the member values.

Can enum have multiple values Python?

Enums can't have multiple value per name.

Do enums have to be unique?

Every enumerator or variable name in the scope must be unique. However, the values can be duplicated. In an unscoped enum, the scope is the surrounding scope; in a scoped enum, the scope is the enum-list itself.

What is the point of enums in Python?

Python's enum module provides a convenient function called auto() that allows you to set automatic values for your enum members. This function's default behavior is to assign consecutive integer values to members.


2 Answers

It appears the answer to my second question was hiding in plain sight in the soure code for enum.py.

Each Enum does contain a dict of value->member pairs for hashable (i.e. immutable) values, and when you look up an Enum by value, it attempts to retrieve the member from that dict. If the value is not hashable, it then brute-force compares for equality against all existing Enum values, returning the member if finds a match. The relevant code is in lines 468-476 in enum.py:

try:
    if value in cls._value2member_map_:
        return cls._value2member_map_[value]
except TypeError:
    # not there, now do long search -- O(n) behavior
    for member in cls._member_map_.values():
        if member._value_ == value:
            return member
raise ValueError("%r is not a valid %s" % (value, cls.__name__))

So it appears as though the designers of enum.py wanted to have a quick lookup when getting Enums by value, but still wanted to give the flexibility of having mutable values for Enum values (even though I still can't think of a reason why someone would want that in the first place).

like image 119
Billy Avatar answered Nov 05 '22 21:11

Billy


It's worth highlighting that enum values can be anything according to the documentation.

Note Enum member values Member values can be anything: int, str, etc.. If the exact value is unimportant you may use auto instances and an appropriate value will be chosen for you. Care must be taken if you mix auto with other values. https://docs.python.org/3/library/enum.html#creating-an-enum

It's a pretty big departure from other enum entities in other languages. The allowance should make for some interesting possibilities however. I like the string as value variant where the source code friendly enum name is used in source while the enum value can serve for presentation purposes as in front-end code or console app help text or something.

like image 2
jxramos Avatar answered Nov 05 '22 22:11

jxramos