代码之家  ›  专栏  ›  技术社区  ›  Jon-Eric

更多的Python转换为二进制?

  •  6
  • Jon-Eric  · 技术社区  · 15 年前

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

    有没有更具可读性/通灵性的方法?

    8 回复  |  直到 15 年前
        1
  •  4
  •   ebo    15 年前

    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的声明性_库、ToscaWidgets和sprox

        2
  •  4
  •   Dave    15 年前
    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()
    
        3
  •  2
  •   jb.    15 年前
        4
  •  2
  •   sth ACP    15 年前

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

    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”,它更像是一种函数式编程方法,但我认为它提高了可读性。

        5
  •  1
  •   mtasic85 Ed Heal    15 年前
    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
            ])
        ])
    
        6
  •  0
  •   gabor    15 年前

    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()
    
        7
  •  0
  •   Darius Bacon    15 年前

        8
  •  0
  •   Nadia Alramli    15 年前

    您可以消除重复,同时仍可以像下面这样轻松阅读:

    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
        )