Saturday, 12 September 2026

Python Enums missing_key

In a recent post about Python enums I mentioned the _missing_ method, that gets executed when accessing an enum member by value if that value is missing.


from enum import Enum
class Color(Enum):
    RED = "red"
    BLUE = "blue"
    @classmethod
    def _missing_(cls, value):
        value = value.lower()
        print(f"missing value: {value}")
        for member in cls:
            if member.value == value:
                return member
        return None

print(Color.RED is Color("red"))
# True

print(Color.RED is Color("rEd"))
# missing value: rEd
# True

We know that we can also get an enum member by name, using the [] syntax (subscripted access or key/name access), like color = Color["RED"], and well, it feels to me that it would be nice to have this kind missing functionality for that kind of access (let's call it 'missing_key'). I mean, defining a sort of missing_key method in our enum classes that would get invoked if the key/name used does not exist. And how can we hook this behaviour into the subscripted access to the enum? At the end of this post I talked about those __dunder_methods__ that work as behavioral hooks. We have hooks for invokation, attribute getting, attibute setting... and also one, __getitem__ for subscripted access. For this case, we'll be using the subscripted access in the class, so we have to implement it in a metaclass. The Enum class has EnumMeta as its metaclass, so we'll need our new metaclass to inherit from EnumMeta. When creating an Enum empowered with this "missing_key" functionality, it'll have to use our new metaclass, and inherit from Enum (or related child classes like IntEnum, StrEnum...).

`EnumMeta` implements the class-creation machinery (turning attributes into members, building `__members__` and `_value2member_map_`), but it relies on the base class (`Enum`) to provide the instance API and the initialization/constructor expectations used when creating each member. Without inheriting from `Enum`, those assumptions break and class creation fails or yields an object that isn't a proper enum.

So we define this metaclass, that when accessing a missing key will invoke a _missing_key method (if it exists) in the enum class.


from enum import EnumMeta, Enum

class MissingKeyEnum(EnumMeta):
    def __getitem__(cls, name):
        try:
            return super().__getitem__(name)
        except KeyError:
            print(f"Name '{name}' is not a valid member of {cls.__name__}")
            # Call a dedicated missing-name handler if present
            if hasattr(cls, "_missing_key"):
                return cls._missing_key(name)
            return None


An now we define a class that leverages the metaclass to allow case insensitive subscripted access:


class Query(Enum, metaclass=MissingKeyEnum):
    SELECT = "select"
    INSERT = "insert"
    UPDATE = "update"
    DELETE = "delete"

    @classmethod
    def _missing_key(cls, name):
        # This method is called when a name is not found in the enum
        # You can customize the behavior here, for example, allowing case insensitive access
        return getattr(cls, name.upper(), None)  # Return the enum member if it exists, otherwise return None



query1 = Query["INSERT"]  # This will return the enum member Query.INSERT
query2 = Query["Insert"]  # This will go through _missing_key and return Query.INSERT
print(query1 is query2)  # This will print True, as both refer to the same enum member

query3 = Query["insssseeerrtt"]  # This will go through _missing_key and return None
print(f"query3: {query3}")  # This will print None, as the name is not valid


Just to close this post I'll mention an interesting article that discusses inheriting from Enum vs using a new metaclass that inherits from EnumMeta.

No comments:

Post a Comment