Enumeraciones en Python
⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.
En Python, las enumeraciones se manejan con la clase Enum
del módulo enum
. Aunque ambas plataformas ofrecen una forma estructurada de trabajar con valores predefinidos, hay diferencias clave en las funcionalidades y en cómo se utilizan las enumeraciones en cada lenguaje.
📌 Definición y Uso Básico
En Python, se pueden definir enumeraciones de la siguiente manera:
from enum import Enum
class DeliveryState(Enum):
PENDING = 0
PAID = 1
SHIPPED = 2
DELIVERED = 3
CANCELLED = 4
Aquí, DeliveryState
es una enumeración que contiene los mismos valores que definimos en Kotlin. Sin embargo, hay algunas diferencias importantes:
- Tipado Estático vs. Dinámico: A diferencia de Kotlin, Python es un lenguaje de tipado dinámico, lo que significa que no se tiene la misma garantía de seguridad de tipos en tiempo de compilación. En Kotlin, el compilador asegura que solo se usen valores válidos de la enumeración, mientras que en Python, los errores relacionados con valores no válidos se detectan en tiempo de ejecución.
- No Exhaustividad: En Python, no hay un mecanismo directo que garantice que se manejan todos los casos de una enumeración. En Kotlin,
when
asegura la exhaustividad, pero en Python, el uso de una sentenciaif-else
no tiene esta garantía automática.
🚀 Uso de auto()
en Enumeraciones
Python proporciona enum.auto()
, una forma conveniente de asignar valores automáticamente a los miembros de una enumeración sin necesidad de definirlos manualmente.
auto()
?✔️ Si no necesitas valores específicos, pero sí una enumeración con valores únicos.
✔️ Si quieres evitar asignar valores manualmente para reducir errores y mejorar la legibilidad.
❌ No es útil si cada miembro debe tener un valor específico (por ejemplo, códigos HTTP o estados con valores predefinidos).
from enum import Enum, auto
class DeliveryState(Enum):
PENDING = auto()
PAID = auto()
SHIPPED = auto()
DELIVERED = auto()
CANCELLED = auto()
print(list(DeliveryState))
# Output: [<DeliveryState.PENDING: 1>, <DeliveryState.PAID: 2>, <DeliveryState.SHIPPED: 3>, <DeliveryState.DELIVERED: 4>, <DeliveryState.CANCELLED: 5>]
Detalles clave sobre auto()
- Los valores asignados comienzan en
1
y aumentan secuencialmente. - No se puede combinar
auto()
con valores manuales dentro de la misma enumeración. - Es útil cuando solo interesa identificar cada estado sin importar su valor numérico.
🔧 Personalización de Métodos
En Python, se pueden agregar métodos a las enumeraciones, similar a Kotlin, pero la forma de hacerlo es un poco diferente:
from enum import Enum
class DeliveryState(Enum):
PENDING = 0
PAID = 1
SHIPPED = 2
DELIVERED = 3
CANCELLED = 4
def signal(self):
return {
DeliveryState.PENDING: "Order is pending",
DeliveryState.PAID: "Order is paid",
DeliveryState.SHIPPED: "Order is shipped",
DeliveryState.DELIVERED: "Order is delivered",
DeliveryState.CANCELLED: "Order is cancelled"
}[self]
🏗️ Implementación de Comportamientos Comunes en Python
Tanto en Kotlin como en Python, es posible definir métodos en las enumeraciones para devolver valores específicos o ejecutar acciones según el estado de la enumeración. Sin embargo, hay diferencias clave entre ambos lenguajes:
- En Kotlin, se pueden definir métodos abstractos dentro de las enumeraciones, lo que obliga a cada valor a proporcionar una implementación específica.
- En Python, esto no es posible de manera nativa. No se puede hacer que cada valor de la enumeración implemente un método de manera obligatoria.
En lugar de interfaces, en Python se puede usar herencia múltiple y mixins para compartir comportamientos comunes entre las enumeraciones.
📌 Ejemplo de herencia múltiple y mixins en enumeraciones
from enum import Enum
class Notifier:
def notify(self, subscriber, message):
print(f"Notifying {subscriber.__class__.__name__}: {message}")
class Storable:
def store(self):
print("Storing data")
class DeliveryState(Enum, Notifier, Storable):
PENDING = ("Order is pending", 0)
PAID = ("Order is paid", 1)
SHIPPED = ("Order is shipped", 2)
DELIVERED = ("Order is delivered", 3)
CANCELLED = ("Order is cancelled", 4)
def __init__(self, description, code):
self.description = description
self.code = code
def signal(self):
return self.description
def is_final_state(self):
return self in (self.DELIVERED, self.CANCELLED)
# Uso
state = DeliveryState.PAID
print(state.signal()) # Output: "Order is paid"
state.notify(object(), "Order is paid") # Output: "Notifying object: Order is paid"
state.store() # Output: "Storing data"
print(state.is_final_state()) # Output: False
🧐 ¿Por qué init() en una enumeración?
Python permite que cada miembro de una enumeración tenga valores adicionales asociados, lo que amplía su funcionalidad más allá de ser simples valores constantes.
En el ejemplo anterior, cada estado de DeliveryState
almacena una descripción (description
) y un código (code
) dentro de la enumeración. Sin embargo, en la mayoría de los casos, las enumeraciones no requieren __init__()
si solo representan valores constantes.
✅ Ejemplo sin __init__()
(solo valores constantes)
from enum import Enum
class SimpleDeliveryState(Enum):
PENDING = 0
PAID = 1
SHIPPED = 2
DELIVERED = 3
CANCELLED = 4
📌 ¿Cuándo usar __init__()
?
- ✔️ Si necesitas almacenar información adicional en cada miembro de la enumeración (como en el caso de
description
ycode
). - ❌ Si solo necesitas valores constantes,
__init__()
es innecesario y puede hacer el código más complejo de lo necesario.
🔍 Acceso y Validación de Valores
En Kotlin, se puede validar y acceder a los valores de la enumeración con métodos como valueOf
. Python ofrece una forma similar:
try:
state = DeliveryState["PAID"]
print(state)
except KeyError:
print("Invalid state")
Python utiliza KeyError
si un valor no existe, mientras que en Kotlin se lanza una IllegalArgumentException
. Ambos lenguajes requieren el manejo explícito de errores si se busca un valor no válido, pero Python no ofrece una función equivalente a entries
para iterar directamente sobre todos los valores de la enumeración, como en Kotlin.
También es posible iterar sobre los valores de la enumeración en Python:
for state in DeliveryState:
print(state)