【问题标题】:Structure with attribute like-c in PythonPython中具有属性like-c的结构
【发布时间】:2021-02-24 10:57:12
【问题描述】:

我想在 C 中创建类似结构的东西,但在 Python 中。具体来说,我想这样:

typedef struct __attribute__((__packed__)) 
{
    float x[4];
    uint8 y;
    int z;
} structName;

在 Python 中。我在某处读到我可以使用命名元组但想避免填充并且我不知道如何在 Python 中做到这一点。谁能告诉我该怎么做?我将在 UDP 通信中使用它。

【问题讨论】:

  • Python 是一种比 C 更高级的语言。没有直接的类似物。您可能想查看dataclassnamedtuple
  • 请说明确切您需要什么。考虑struct作为数据布局,struct比较合适。将struct 视为数据抽象,dictclassnamedtupledataclass 或类似名称是合适的。考虑到struct 作为序列化基础,格式化bytes 的函数可能是合适的。
  • @MisterMiyagi 将此作为答案 :)

标签: python c padding


【解决方案1】:

如果您想序列化(例如:保存到文件或通过网络发送),您应该查看struct 库,基本上您可以定义如何保存数据、多少字节和哪种顺序。

您可以在 python 中使用一个类来表示您的结构,并添加两个函数将其打包成较小的二进制数据,并在您再次需要时将其解包

你的例子应该是:

import struct

class StructName():
    def __init__(self, xs=None, y=None, z=None):
        self.xs = xs
        self.y = y
        self.z = z

    def pack(self):
        return struct.pack("!4fBi", *self.xs, self.y, self.z)

    def unpack(self, packed_bytes):
        *self.xs, self.y, self.z = struct.unpack("!4fBi", packed_bytes)

if __name__ == "__main__":
    s = StructName([1.0, 0.5, 2.0, 0.], 255, 42)
    tmp = StructName()
    bytedata = s.pack()
    print("s", s.xs, s.y, s.z) # s [1.0, 0.5, 2.0, 0.0] 255 42
    print(len(bytedata), bytedata) # 21 b'\x00\x00\x80?\x00\x00\x00?\x00\x00\x00@\x00\x00\x00\x00\xff\x00\x00\x00*\x00\x00\x00'
    tmp.unpack(bytedata)  # fill data into tmp class
    tmp.xs[0] = 42.5
    print("tmp", tmp.xs, tmp.y, tmp.z) # tmp [42.5, 0.5, 2.0, 0.0] 255 42

packunpack 函数中的格式字符串为“!4fBi”,其中:

  • ! - 使用网络字节顺序(bigendian)
  • 4f - 四个浮点数(4*4 字节)
  • B - 一个无符号字符(1 个字节)
  • i - 一个有符号整数(4 字节)

欲了解更多信息,请查看此部分:Format Characters

【讨论】:

  • 非常感谢您的宝贵时间。我想问一下self.xs之前的'*'是什么意思
  • @KrysPy '*' 会将来自struct.unpack 函数结果的值打包到一个列表中,除了最后两个值将分配给yz。一个例子:*ls, last = (1, 2, 3, 4) 在这种情况下,last 将是 4ls 等于 [1, 2, 3]
  • 还有一个问题。我可以在格式字符串中使用我自己的类对象吗?例如,当我在一个模块中创建类,然后我想获取这种类型的结构数据(这个新创建的类的类型)。
  • @KrysPy 我很难理解你的确切问题是什么。如果你想在多个模块中使用这个类,你应该把它移到一个单独的模块中(比如:models.pydata_structures.py)并从那里导入到那些您想在其中使用它们的模块。在格式字符串中只能使用struct文档中描述的那些字符:docs.python.org/3/library/struct.html#format-characters
  • 好的,对于难以理解的问题很抱歉,这很难解释,但你已经帮了我很多。再次感谢您。
【解决方案2】:

在已接受答案的评论部分回答评论

import re
import struct


def get_values_from_binary(format_str, bin_data):
    val_regex = re.compile(r"[a-zA-Z]([0-9]+)?")
    ls = struct.unpack(format_str, bin_data)
    res = []
    i = 0
    for m in val_regex.finditer(format_str):
        groups = m.groups()
        current_length = 1
        if groups is not None and groups[0] is not None:
            current_length = int(groups[0])
        res.append(ls[i:i + current_length])
        i += current_length
    return res


if __name__ == "__main__":
    f_str = "<I7f7f7f3f4ffI"
    data = [0]*7 + [0.3]*7 + [0.5]*7 + [0.9]*3 + [1.0]*4 + [2.5, 3.5, 1]
    print(data)
    bindata = struct.pack(f_str, *data)
    unpacked_data = get_values_from_binary(f_str, bindata)
    print(unpacked_data)

【讨论】:

  • 我终于在 unpack 方法中完成了这个。我刚刚从解包到类中的属性后生成的元组中分配了适当的元素,并且它可以工作。非常感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-01
  • 2018-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-06
相关资源
最近更新 更多