【问题标题】:How to serialize/encode a custom object to bytes/bytearray?如何将自定义对象序列化/编码为字节/字节数组?
【发布时间】:2021-05-25 11:43:11
【问题描述】:

我有以下 python 类:

class Header:
  def __init__(self, id, len):
    self.id = id
    self.len = len

h = Header(1, 10)

如何序列化/编码此类的实例,hbytesbytearray,例如可以写入 socket

为了提供更多的视角,我需要将此对象写入一个 C++ 程序正在侦听以接收上述对象的 unix 域套接字(它定义上述 struct 与上述完全相同,具有相同的数量/类型字段)。 pickle.dump(...) 编码不起作用。

C++ 结构是:

typedef struct Header {
  uint32_t id;
  uint32_t len;
}

事实上,我可以通过Go 与这个C++ 程序进行交互,如下所示。

import (
  "bytes"
  "encoding/binary"
)

type Header struct {
  ID uint2
  Len uint32
}

// output of this function is written to the socket opened by C++ and it works!!
func GetHeaderBuf() *bytes.Buffer, error{
  hdrBuf := new(bytes.Buffer)
  hdr := Header{1, 10}
  if err := binary.Write(hdrBuf, binary.LittleEndian, hdr); err != nil {
    return nil, err
  }
  return hdrBuf, nil
}

我正在寻找的是上面 Go 代码行 binary.Write(...) 的 python 等效项。

【问题讨论】:

  • 套接字问题可能在这里得到解答:stackoverflow.com/a/28519877/2359945。我可以看到很难筛选结果,我不得不自己戳到大约 6 个左右。希望这对您有所帮助。将来,请考虑分享您研究过的一些链接以及它们如何达不到您的期望。
  • “它定义了上面的结构,与上面完全相同,具有相同数量/类型的字段”——什么结构和什么类型?您正在显示具有任意类型的任意字段的任意类。请注意,如果您有兴趣将 C 结构表示为“数据布局”,Python 有一个模块,字面意思是 struct

标签: python c++ python-3.x go


【解决方案1】:

这叫Serialization

在 Python 中,您可以使用标准库 pickle 模块自动执行(反)序列化或手动序列化。在后一种情况下,您决定要编码的各个属性以及编码它们的方式。然后struct 模块进行实际的字节转换。

pickle方式:

data = pickle.dumps(h)
h2 = pickle.loads(data)

手动方式:

假设我们需要 2 个字节来存储一个 id(小于 65636)和 4 个字节来存储一个 len。我们可以做

data = struct.pack('>hi', h.ID, h.Len)
h2 = Header(*struct.unpack('>hi', data))

Pickling 使用内部格式,只能在 Python 应用程序之间使用。另一方面,struct 特别适用于异构应用程序。这里> 表示整数值应该使用所谓的网络顺序(大)字节序。这简化了不同架构之间交换值的过程。

如果另一部分使用 C 语言,struct 无疑是要走的路。

【讨论】:

【解决方案2】:

没错。首先,我想指出这一点:

     ID = 0                                                                                                  
     Len = 0

完全没用。它所做的只是在类上添加两个属性。除此之外,您还没有遵守 Python 命名约定:

  • 属性为snake_cased
  • 没有阴影内置函数(idlen 是)。

无论如何,有几十种方法可以将内容编码为字节,因此您首先需要决定要使用哪个交换协议,这取决于另一端的内容插座。

从用户体验的角度来看,最简单的解决方案是pickle,序列化对象是事情的全部重点,它可以开箱即用,但它也是最危险的(因为泡菜是与 python 相邻的字节码,所以 pickle 输入本质上是远程代码执行),而且它 100% 仅适用于 Python。

另一方面是json,它得到了各种语言的难以置信的良好支持,但对 Python 一无所知,因此您需要一个定制的编码器(另一端可能还有一个定制的解码器)如果它也是 Python)。

除了不被标准库直接支持之外,还有一些第三方库(例如 messagepack、flatbuffers 等)有各种权衡。

【讨论】:

  • 感谢您对 python 约定的评论;我从 Go 复制了一个结构来快速发布问题。现在编辑了。
  • 如果你从 Go 复制一个结构,你可能需要在套接字的另一端与 Go 接口/交互?在这种情况下,JSON 和自定义编码器很可能是可行的方法。
  • 实际上我正在尝试从 Go(成功完成)和 python(进行中)与 C++ 交互。
  • 啊,如果你这样做,那么你可能已经有某种序列化协议。在这种情况下,如果您在 Go 和 C++ 之间使用 ad-hoc 协议,您可能需要使用 struct 模块并完全手动序列化您的实例。 struct 让您可以用 C 语言对二进制数据进行低级转换(控制字节顺序、特定输出大小……)。
猜你喜欢
  • 2013-04-29
  • 2014-09-02
  • 2016-04-18
  • 2014-12-07
  • 1970-01-01
  • 2016-03-23
  • 2015-06-03
  • 2016-05-08
  • 2023-01-31
相关资源
最近更新 更多