Python中将Redis读取的二进制枚举值转换为Enum类型的方法
嘿,这个问题我之前做项目的时候也踩过坑!Redis本身是个键值对数据库,只认字符串、二进制这类基础数据类型,你直接把Enum实例存进去的话,其实是把它的字符串表示(比如Position.LEFT)转成二进制存了,读出来自然就是b'Position.LEFT'这种字节串。要把它转回到对应的Enum实例,有几种靠谱的方案,我给你详细说说:
方法1:存储Enum的数值(Value),最安全高效
这是我最推荐的方案,因为数值存储体积小,解析速度快,还不会有歧义。核心思路是存Enum实例的.value属性,读取后直接用Enum类转换。
from enum import Enum import redis # 初始化Redis连接 r = redis.Redis(host='localhost', port=6379, db=0) class Position(Enum): LEFT = 10 RIGHT = 11 # 存储Enum的value current_position = Position.LEFT r.set('current_position', current_position.value) # 读取并转换为Enum实例 loaded_value = int(r.get('current_position')) loaded_current_position = Position(loaded_value) print(loaded_current_position) # 输出:Position.LEFT
优点:存储数据量极小,解析速度快,不存在字符串解析的歧义,完全没有安全风险;缺点:Redis中存储的是数字,可读性稍差(但可以通过注释或文档弥补)。
方法2:存储Enum的名称(Name),可读性更强
如果需要在Redis里直接看到存储的是LEFT还是RIGHT(方便调试),可以存Enum实例的.name属性,读取后通过Enum[name]获取对应实例。
# 存储Enum的name r.set('current_position', current_position.name) # 读取并转换为Enum实例 loaded_name = r.get('current_position').decode('utf-8') # 先把字节串转成字符串 loaded_current_position = Position[loaded_name] print(loaded_current_position) # 输出:Position.LEFT
优点:Redis中的值可读性极高,调试时一目了然;缺点:如果后续修改了Enum的name(比如把LEFT改成LEFT_SIDE),旧数据会直接失效,需要同步更新Redis中的值。
方法3:用pickle序列化(谨慎使用)
如果你的Enum结构复杂(虽然一般Enum不需要),或者想直接存储整个实例的状态,可以用Python的pickle模块序列化后存储,读取时反序列化。但一定要注意:pickle存在安全风险,绝对不要反序列化来自不可信来源的数据!
import pickle # 序列化Enum实例并存储 r.set('current_position', pickle.dumps(current_position)) # 读取并反序列化 loaded_data = r.get('current_position') loaded_current_position = pickle.loads(loaded_data) print(loaded_current_position) # 输出:Position.LEFT
优点:不需要手动处理属性,直接存/取实例;缺点:存储的是二进制Blob,完全不可读,数据体积大,且有安全隐患。
进阶技巧:自定义Redis解析器(自动转换)
如果你经常需要存/取Enum,可以给redis-py注册一个自定义解析器,让它自动处理序列化和反序列化,不用每次手动转换:
from redis.connection import DefaultParser class EnumParser(DefaultParser): def __init__(self, enum_cls, *args, **kwargs): super().__init__(*args, **kwargs) self.enum_cls = enum_cls def parse_response(self, connection, command_name, **options): response = super().parse_response(connection, command_name, **options) # 对GET/HGET命令的返回值自动转换 if command_name in ['GET', 'HGET'] and isinstance(response, bytes): try: # 先尝试用value转换(对应方法1) return self.enum_cls(int(response)) except ValueError: # 失败则用name转换(对应方法2) return self.enum_cls[response.decode('utf-8')] return response # 使用自定义解析器初始化Redis连接 r = redis.Redis(host='localhost', port=6379, db=0, parser=EnumParser(Position))
这样后续你直接用r.get('current_position')就能拿到对应的Enum实例,完全不用手动处理转换!
内容的提问来源于stack exchange,提问作者Eric Baldwin




