实现一个比Enum更好用的EnumPro枚举类

85 阅读2分钟

在项目中使用枚举的时候你是否会存在以下问题:

  • 定义泛滥,用类?用mapping?
  • 多端定义,服务端和客户端都定义一遍
  • 中英混杂

自定义枚举类

一般情况我们用 EnumIntEnum 定义枚举类,如果是服务端返回枚举的话,还要定义一个枚举的中英映射关系。现在我想实现这3个需求:

  1. 获取某个枚举全部属性的中英映射字典
  2. 获取某个枚举全部属性的options列表作为前端下拉选项
  3. 获取某个枚举属性的属性名、属性值、中文描述

通过重写python内置枚举类来实现这一需求。

from enum import Enum, IntEnum

class EnumPro(Enum):
    def __new__(cls, value, desc):
        obj = object.__new__(cls)
        obj._value_ = value
        obj.desc = desc
        return obj
    
    @classmethod
    def mappings(cls):
        return {c._value_: c.desc for c in cls}
    
    @classmethod
    def options(cls):
        return [{"name": c.desc, "value": c.value} for c in cls]


class IntEnumPro(IntEnum):
    def __new__(cls, value, desc):
        obj = int.__new__(cls, value)
        obj._value_ = value
        obj.desc = desc
        return obj
    
    @classmethod
    def mappings(cls):
        return {c._value_: c.desc for c in cls}
    
    @classmethod
    def options(cls):
        return [{"name": c.desc, "value": c.value} for c in cls]
    
    
class StateEnum(EnumPro):
    ENABLED = "enabled", '启用'
    DISABLED = "disabled", '禁用'
    DELETED = "deleted", '删除'
    
    
class OrderState(IntEnumPro):
    CANCELLED = -1, "已取消"
    UNPAID = 0, "未支付"
    PAID = 1, "已支付"


print(StateEnum.ENABLED.name)  # ENABLED
print(StateEnum.ENABLED.value) # enabled
print(StateEnum.ENABLED.desc)  # 启用
print(OrderState.mappings())   # {-1: '已取消', 0: '未支付', 1: '已支付'}
print(OrderState.options())    # [{'name': '已取消', 'value': -1}, {'name': '未支付', 'value': 0}, {'name': '已支付', 'value': 1}]

python中还可以用 MappingProxyTyp 定义不可变字典

STATE_MAP = MappingProxyType(
    {
        "enabled": "启用",
        "disabled": "禁用",
    }
)

如何选择?

数据库中可以用smallint、varchar、enum类型存储枚举字段。
如果枚举属性不超过20个,建议用smallint类型,因为smallint只占用2字节;超过20个可以用字符串类型,利于业务上的拓展和理解,不过具体还是得根据实际业务来决定,不建议用数据库的enum类型,删除或修改会很麻烦。