更多Pythonic转换为二进制?

时间:2009-05-21 17:39:35

标签: python

这是一个人为的例子,说明我们的很多类如何返回自己的二进制表示(由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字段,您不必触摸多行代码。

有更可读/ pythonic的方法吗?

8 个答案:

答案 0 :(得分:4)

您可以尝试为您的数据实施某种declarative syntax

这可能导致类似:

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

答案 1 :(得分: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()

答案 2 :(得分:2)

如果您只想要更好的语法,可以滥用生成器/装饰器:

from functools import wraps    

def packed(g):
  '''a decorator that packs the list data items
     that is generated by the decorated function
  '''
  @wraps(g)
  def wrapper(*p, **kw):
    data = []
    for params in g(*p, **kw):
      fmt = params[0]
      fields = params[1:]
      data.append(struct.pack('<'+fmt, *fields))
    return ''.join(data)    
  return wrapper

@packed
def as_binary(self):
  '''just |yield|s the data items that should be packed
     by the decorator
  '''
  yield 'I', [2]
  yield 'II', self.image.size[0], self.image.size[1]
  yield 'I', len(self.attributes)

  for attribute in self.attributes:
    yield 'I', attribute.id
    yield 'H', attribute.type
    if attribute.type == 0:
      yield 'I', attribute.typeEx

基本上,它使用生成器来实现“monad”,这是一种通常在Haskell等函数式语言中找到的抽象。它将某些值的生成与决定如何将这些值组合在一起的代码分开。它更像是一种函数式编程方法,然后是“pythonic”,但我认为它提高了可读性。

答案 3 :(得分:2)

protocol buffers谷歌广泛的跨语言格式和共享数据协议怎么样?

答案 4 :(得分:1)

def to_binary(self):
    struct_i_pack = struct.Struct('<I').pack
    struct_ii_pack = struct.Struct('<II').pack
    struct_h_pack = struct.Struct('<H').pack
    struct_ih_pack = struct.Struct('<IH').pack
    struct_ihi_pack = struct.Struct('<IHI').pack

    return ''.join([
        struct_i_pack(2),
        struct_ii_pack(*self.image.size),
        struct_i_pack(len(self.attributes)),
        ''.join([
            struct_ih_pack(a.id, a.type) if a.type else struct_ihi_pack(a.id, a.type, a.typeEx)
            for a in attributes
        ])
    ])

答案 5 :(得分:0)

您可以重构代码以将样板包装在类中。类似的东西:

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

    # Binary version number.
    binary.pack('<I', [2])

    # alternatively, you can pass an array
    stuff = [
        ('<II', *self.image.size),          # Image size.
        ('<I', len(self.attributes)),       # Attribute count
    ]
    binary.pack_all(stuff)

    return binary.get_packed()

答案 6 :(得分:0)

最糟糕的问题是你需要在C ++中使用相应的代码来读取输出。您是否可以合理安排将读写代码机械地衍生自或使用通用规范?如何解决这个问题取决于你的C ++需求和Python一样多。

答案 7 :(得分:0)

你可以像以下一样轻松地阅读重复:

def to_binary(self):     
    output = struct.pack(
        '<IIII', 2, self.image.size[0], self.image.size[1], len(self.attributes)
    )
    return output + ''.join(
        struct.pack('<IHI', attribute.id, attribute.type, attribute.typeEx)
        for attribute in self.attributes
    )
相关问题