You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:33:25