Skip to main content

Python Enum Number reverse lookup

· 6 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

Reverse lookup is the process of retrieving the symbolic member name (e.g., NOT_FOUND) or the member object itself from its associated raw value (e.g., 404). This is an essential technique when dealing with external inputs like HTTP status codes, database keys, or configuration settings.

This article details the most efficient and robust methods for performing reverse lookup using the standard Python enum.Enum library.

Setup and Base Enum

We'll use two Enum types: one with unique values and one with a duplicate value to illustrate advanced lookup handling.

from enum import Enum, unique
from typing import Dict, Any

# Standard Unique Value Enum
class HttpCode(Enum):
OK = 200
NOT_FOUND = 404
SERVER_ERROR = 500

# Enum with a Duplicate Value (Alias)
# Python treats the alias as part of the Enum, but the primary lookup is ambiguous
class StatusAlias(Enum):
ACTIVE = 1
ENABLED = 1 # Alias for ACTIVE
INACTIVE = 0

Method: Direct Constructor Call (The Standard Way)

The built-in Enum constructor is the simplest and most Pythonic way to perform reverse lookup. If a value is passed to the Enum class, the class attempts to return the corresponding member.

# Example 1: Basic Reverse Lookup
raw_value = 404
member_object = HttpCode(raw_value)

print(f"Member Object: {member_object}")
# Output: HttpCode.NOT_FOUND

print(f"Member Name: {member_object.name}")
# Output: NOT_FOUND

# Example 2: Handling Invalid Values
try:
HttpCode(999)
except ValueError as e:
print(f"Invalid Value Error: {e}")
# Output: Invalid Value Error: 999 is not a valid HttpCode

Method: Using the Internal Member Mapping

Enums maintain an internal, hidden dictionary called _value2member_map_ that maps all values to their corresponding primary member object. This dictionary is highly efficient for direct reverse lookup, especially for complex or composite values.

# Example 3: Direct Access via Internal Mapping
raw_value = 500
member_map = HttpCode._value2member_map_
member_object_direct = member_map.get(raw_value)

print(f"Lookup via map: {member_object_direct}")
# Output: HttpCode.SERVER_ERROR

# Example 4: Handling Alias/Duplicate Values (Crucial Distinction)
# The internal map only stores the *first* member defined for a given value.
alias_map = StatusAlias._value2member_map_
member_from_alias = alias_map.get(1)

print(f"Alias Lookup Result: {member_from_alias}")
# Output: StatusAlias.ACTIVE
# Annotation: Although ENABLED has the same value, ACTIVE is returned because it was defined first.

Method: Caching for Performance (Creating a Custom Lookup Dictionary)

While the internal map (_value2member_map_) is fast, sometimes you need to guarantee that the mapping is exactly value-to-name (not value-to-member-object) or you need to process the values before lookup. Creating a cached dictionary at startup is the best approach for critical performance paths.

# Example 5: Creating a Cached Value-to-Name Lookup Dictionary
def create_value_to_name_cache(enum_class: Enum) -> Dict[Any, str]:
"""Generates a cached dictionary mapping value to name."""
return {member.value: member.name for member in enum_class}

HTTP_CODE_CACHE = create_value_to_name_cache(HttpCode)

raw_value = 404
name_lookup = HTTP_CODE_CACHE.get(raw_value)

print(f"Cached Name: {name_lookup}")
# Output: NOT_FOUND

Method: Checking for Member Existence and Iteration

If you need to check if a value is valid without raising a ValueError, or if you need to iterate through possible matches, direct iteration or membership checking is necessary.

# Example 6: Checking if a Value is Valid (Without raising)
def is_valid_http_code(value: Any) -> bool:
"""Returns True if the value exists in the Enum, False otherwise."""
return value in HttpCode._value2member_map_

print(f"Is 200 valid? {is_valid_http_code(200)}")
print(f"Is 999 valid? {is_valid_http_code(999)}")
# Output: True
# Output: False

# Example 7: Iterating through All Members (Using the __members__ dictionary)
# The __members__ dict maps name -> member object, including aliases.
all_members = StatusAlias.__members__
print(f"Total members (including alias): {len(all_members)}")

# Output: 3 (ACTIVE, ENABLED, INACTIVE)

Sources and Further Reading

  1. Python Documentation - enum.Enum Constructor
  2. Python Documentation - Internal Attributes (_value2member_map_)
  3. Python Documentation - Iterating and Member Access
  4. Real Python - Python Enum Reverse Lookup