I'm trying to achieve the following behavior in a python "enum" (so far to no success):
Given the enum class
class MyEnum(enum.Enum):
    A=1
    B=2
    C=3
I want to have an "Other" member such that MyEnum(5) will be interpreted as "Other", while retaining the value 5, or, 
>>> str(MyEnum(5))
... "<MyEnum.Other: 5>"
I thought of doing something along the line of overriding the _missing_ function, but I don't know how to create a "custom" instance of MyEnum without rewriting EnumMeta.
Advices will be appreciated.
EDIT: Following some comments that fail to understand my question precisely, I do not wish to have a default value for the enum, as this default value will not retain the value (that I wish to keep). I wish only that the value will be accepted with a default name.
As the saying goes, if you want something done... I created the following enum subclass (I didn't add any new members so that's allowed):
class DefaultNameEnum(Enum):
    """Support for "Other"/default-name values"""
    @classmethod
    def _missing_(cls, value):
        possible_member = cls._value2member_map_.get(value, None)
        if possible_member is None:
            possible_member = cls._create_pseudo_member_(value)
        return possible_member
    @classmethod
    def _create_pseudo_member_(cls, value):
        """
        Create a default-name member.
        """
        default_member = cls._value2member_map_.get(None, None)
        if default_member is None:
            raise ValueError("%r is not a valid %s" % (value, cls.__name__))
        # construct a singleton enum pseudo-member
        other_member = object.__new__(cls)
        other_member._name_ = default_member._name_
        other_member._value_ = value
        # use setdefault in case another thread already created a composite
        # with this value
        other_member = cls._value2member_map_.setdefault(value, other_member)
        return other_member
    def __eq__(self, other):
        """Overrides the default implementation"""
        if isinstance(other, DefaultNameEnum):
            return self._name_ == other._name_
        return False
    def __ne__(self, other):
        return not self == other
This is based on the Flag enum subclass. Its usage is quite simple, actually - Just define as None whichever name you wish to have as your default. It is best illustrated using an example - consider the class:
class ABC(DefaultNameEnum):
    A = 1
    B = 2
    C = 3
    Other = None
Than, the following console calls will give:
>>> print([repr(mem) for mem in ABC]) ... ['<ABC.A: 1>', '<ABC.B: 2>', '<ABC.C: 3>', '<ABC.Other: None>'] >>> ABC(123) ... '<ABC.Other: 123>' >>> ABC(1) == ABC(2) ... False >>> ABC(123) == ABC.Other ... True >>> ABC(123) == ABC(1374) ... True
If you wish to take this implementation and use it, note the following points:
The behavior in the last line might be wanted and might not - depending on your usage. If this is an unwanted usage, just change the __eq__ method to compare names when either self._value_ or other._value_ are None.
If you use this class, for the sake of representability you might wish for the default value's __repr__ to output '<ABC.Other>' rather than '<ABC.Other: None>' in the case of None value. This could easily be accomplished by overriding the __repr__ method.
If you don't define a default member, the class will raise an exception upon calling it upon an unknown value (just like any Enum subclass).
I also wish to note that in the above implementation I would've preferred to use a sunder member such as _default_name_ or _default_value_member_ rather than assigning None, but alas the enum module does not permit defining a new sunder member for Enum subclasses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With