基于C结构的bytearray转字典:Pythonic实现及字节转字符串问题
问题
我通过C结构体将bytearray转换为Python对象,且该转换支持双向操作。现在需要一种Pythonic的方式将此对象转换为字典。试用dictfier模块时,发现字节数组类型的字符串会被拆分为单个字节成员,无法直接得到完整字符串。期望转换后的字典可通过s['val1']、s['my_nest']['val10']等方式访问,且val11能直接呈现为完整字符串,而非单个字节的列表。
附上相关代码:
import ctypes as ct import struct class MyNestedStruct(ct.Structure): _pack_ = 1 _fields_ = (('val10', ct.c_int32), ('val11', ct.c_uint8 * 8),) class MyStruct(ct.Structure): _pack_ = 1 _fields_ = (('val1', ct.c_int32), ('val2', ct.c_int32), ('val3', ct.c_int32), ('val4', ct.c_int32), ('my_nest', MyNestedStruct)) def vdd_decode_from_bytes(bin_bytes): return MyStruct.from_buffer_copy(bin_bytes) data = bytes.fromhex('acfffffffaffffffb2ffffff2400000001') s = vdd_decode_from_bytes(data) print(s) # via __repr__ print(s.val1) # still access individual values print(s.val2) print(s.val3) print(s.val4) print(s.my_nest) print(bytes(s).hex()) # convert back to byte stream (shown as hex)
解决方案
1. 自定义递归转换函数
自己实现递归转换逻辑,针对ctypes数组类型做特殊处理,直接转成字符串:
def struct_to_dict(obj): result = {} if hasattr(obj, '_fields_'): for field_name, field_type in obj._fields_: value = getattr(obj, field_name) # 处理子结构体,递归转换 if hasattr(field_type, '_fields_'): result[field_name] = struct_to_dict(value) # 处理ctypes数组,转成字符串(这里用ASCII编码,可按需调整) elif isinstance(value, ct.Array): result[field_name] = bytes(value).decode('ascii').rstrip('\x00') # 基础类型直接取值 else: result[field_name] = value return result # 使用示例 s_dict = struct_to_dict(s) print(s_dict['val1']) print(s_dict['my_nest']['val10']) print(s_dict['my_nest']['val11']) # 输出完整字符串
2. 优化dictfier的使用
如果要保留dictfier的使用,可自定义数组类型的处理逻辑:
from dictfier import dictfier, handlers # 自定义ctypes数组转换器 def ctypes_array_handler(obj, **kwargs): if isinstance(obj, ct.Array): return bytes(obj).decode('ascii').rstrip('\x00') return handlers.default_handler(obj, **kwargs) # 注册转换器 dictfier.add_handler(ct.Array, ctypes_array_handler) # 转换结构体到字典 s_dict = dictfier(s) print(s_dict['my_nest']['val11']) # 正常输出完整字符串
3. 支持双向转换的扩展
如果需要从字典转回ctypes对象,可补充反向转换函数:
def dict_to_struct(d, struct_type): obj = struct_type() for field_name, field_type in struct_type._fields_: value = d[field_name] # 子结构体递归转换 if hasattr(field_type, '_fields_'): setattr(obj, field_name, dict_to_struct(value, field_type)) # 字符串转回ctypes数组 elif issubclass(field_type, ct.Array): arr_len = field_type._length_ # 编码字符串,不足补0,过长截断 byte_data = value.encode('ascii').ljust(arr_len, b'\x00')[:arr_len] # 给数组逐个赋值 for i in range(arr_len): getattr(obj, field_name)[i] = byte_data[i] # 基础类型直接赋值 else: setattr(obj, field_name, value) return obj # 使用示例:字典转回结构体 new_s = dict_to_struct(s_dict, MyStruct) print(bytes(new_s).hex()) # 与原数据一致,实现双向转换
内容的提问来源于stack exchange,提问作者gthorsten
相关产品推荐
相关产品推荐

