更优雅的二进制转换?

6 投票
8 回答
685 浏览
提问于 2025-04-15 11:45

这里有一个例子,展示了我们很多类是如何返回它们自己的二进制表示(可以被C++读取)的。

def to_binary(self):
    'Return the binary representation as a string.'
    data = []

    # Binary version number.
    data.append(struct.pack('<I', [2]))

    # Image size.
    data.append(struct.pack('<II', *self.image.size))

    # Attribute count.
    data.append(struct.pack('<I', len(self.attributes)))

    # Attributes.
    for attribute in self.attributes:

        # Id.
        data.append(struct.pack('<I', attribute.id))

        # Type.
        data.append(struct.pack('<H', attribute.type))

        # Extra Type.        
        if attribute.type == 0:
            data.append(struct.pack('<I', attribute.typeEx))

    return ''.join(data)

我不喜欢的地方:

  • 每一行都以 data.append(struct.pack( 开头,这让人分心,没法专注于这一行的重点。
  • 字节顺序('<')重复出现,让人觉得烦。
  • 你得记得返回那段固定的代码 ''.join(data)

我喜欢的地方:

  • 格式说明符靠近属性名,这样很容易看出 self.image.size 是用两个无符号整数表示的。
  • 这些行(大部分)是独立的。比如,要从一个“属性”中移除Id字段,你只需要改一行代码。

有没有更易读、更符合Python风格的方法来做到这一点呢?

8 个回答

2

你觉得谷歌的 协议缓冲区 怎么样?它是一种可以在不同编程语言之间共享数据的格式和协议,功能非常强大。

4

你可以尝试为你的数据实现一种类似于声明式语法的东西。

这样可能会得到像下面这样的结果:

class Image(SomeClassWithMetamagic):
    type = PackedValue(2)
    attribute = PackedValue('attributes') # accessed via self.__dict__

#or using decorators
    @pack("<II")
    def get_size():
        pass

#and a generic function in the Superclass
    def get_packed():
        stuff

等等...

其他的例子包括SQLAlchemy的declarative_base、ToscaWidgets和sprox。

4

在编程中,有时候我们会遇到一些问题,可能是因为代码写得不够好,或者是我们对某些概念理解得不够透彻。比如,有人可能会在使用某个功能时,发现它的表现和预期不一样。这种情况通常需要我们仔细检查代码,看看哪里出了问题。

另外,编程语言和工具的使用也会影响我们的代码运行效果。有些功能在不同的环境下表现可能会有所不同,所以我们需要了解这些工具的特性,才能更好地使用它们。

总之,编程是一门需要不断学习和实践的技能,遇到问题时不要气馁,仔细分析,逐步解决,才能不断进步。

from StringIO import StringIO
import struct

class BinaryIO(StringIO):
    def writepack(self, fmt, *values):
        self.write(struct.pack('<' + fmt, *values))

def to_binary_example():
    data = BinaryIO()
    data.writepack('I', 42)
    data.writepack('II', 1, 2)
    return data.getvalue()

撰写回答