关于Python序列化/反序列化的问题

1 投票
1 回答
725 浏览
提问于 2025-04-15 21:06

我想知道我有多大的机会去创建、保存并将Python类的实例转换成二进制数据,这些类遵循这个模式(这个模式来自RFC 2246 [TLS]):

   enum { apple, orange } VariantTag;
   struct {
       uint16 number;
       opaque string<0..10>; /* variable length */
   } V1;
   struct {
       uint32 number;
       opaque string[10];    /* fixed length */
   } V2;
   struct {
       select (VariantTag) { /* value of selector is implicit */
           case apple: V1;   /* VariantBody, tag = apple */
           case orange: V2;  /* VariantBody, tag = orange */
       } variant_body;       /* optional label on variant */
   } VariantRecord;

基本上,我需要定义一个(变体)类叫做VariantRecord,这个类的内容会根据VariantTag的值而变化。这并不难。真正的挑战是找到一种最通用的方法来构建一个类,使其能够将数据转换成字节流并再转换回来……像Pickle、Google协议缓冲区、marshal这些都不适用。

我尝试在我的类中明确地定义一个“def serialize”,但效果不太理想,因为它不够通用。

我希望我能清楚地表达这个问题。

如果VariantTag的值是apple,我当前的解决方案看起来是这样的,但我对此并不太满意。

import binascii
import struct

class VariantRecord(object):
  def __init__(self, number, opaque):
    self.number = number
    self.opaque = opaque
  def serialize(self):
    out = struct.pack('>HB%ds' % len(self.opaque), self.number, len(self.opaque), self.opaque)
    return out


v = VariantRecord(10, 'Hello')
print binascii.hexlify(v.serialize())

>> 000a0548656c6c6f

祝好

1 个回答

0

有两个建议:

  1. 对于可变长度的结构,使用固定格式,然后只需切割结果。
  2. 使用 struct.Struct

例如,如果我理解你的格式没错的话(你提到的示例中出现的长度字节,其他变体中也有吗?)

>>> import binascii
>>> import struct
>>> V1 = struct.Struct(">H10p")
>>> V2 = struct.Struct(">L10p")
>>> def serialize(variant, n, s):
    if variant:
        return V2.pack(n,s)
    else:
        return V1.pack(n,s)[:len(s)+3]

    
>>> print binascii.hexlify(serialize(False, 10, 'hello')) #V1
000a0568656c6c6f
>>> print binascii.hexlify(serialize(True, 10, 'hello')) #V2
0000000a0568656c6c6f00000000
>>> 

撰写回答