【问题标题】:How to convert a list with multiple types to binary in Python?如何在 Python 中将具有多种类型的列表转换为二进制?
【发布时间】:2012-08-16 02:30:21
【问题描述】:

我有一个包含两个元素的数组:第一个是类型,第二个是我需要转换的数据数组。

[['string','int32','string','int64','float32','string','string'],['any string','19','any string','198732132451654654','0.6','any string','any string']]

我知道如何将整数转换为二进制,但是在上面的多个类型的数组中,如何将其转换为二进制?

【问题讨论】:

  • 你想做什么? id(o) 将给出对象的“二进制”表示(物理地址)-但我确定这不是您想要的
  • 您的第二个列表是一堆字符串。所以你的问题是如何根据第一个列表中的类型转换第二个列表?
  • @BurhanKhalid 是的,我需要在 python 中将“基于第一个列表中的类型的第二个列表”转换为二进制数据(使用 struct.pack)。感谢您的帮助

标签: python


【解决方案1】:

这是一个很好的方法:

data = [['string','int32','string','int64','float32','string','string'],
        ['any string','19','any string','198732132451654654','0.6',
         'any string','any string']]

type_map = {'string': str, 'int32': int, 'int64': long, 'float32': float}
results = [type_map[t](d) for t, d in zip(data[0], data[1])]
print results

结果:

['any string', 19, 'any string', 198732132451654654L, 0.6, 'any string', 'any string']

这通过在type_map 字典中使用类型字符串作为第一个列表中每个项目的键来查找转换函数来创建结果列表,然后使用第二个列表中的相应数据项调用它。可以在列表声明中使用 for 循环创建列表,方法是使用称为 list comprehension 的东西。此处使用zip 函数为循环的每次迭代从每个子列表创建值对。

【讨论】:

    【解决方案2】:

    虽然您已经接受了我的其他答案,但在注意到您的评论解释说您真正想要的是使用 struct.pack() 将数据转换为二进制之后,我写了另一个可能更适合您的答案(尽管更长并且稍微复杂一点)。

    import struct
    
    class TypeConv(object):
        BSA = '='  # native Byte order, standard Size, with no Alignment
        def __init__(self, conv_func, fmt_chr):
            self.__dict__.update(conv_func=conv_func, fmt_chr=fmt_chr)
    
        def pack(self, data):
            py_value = self.conv_func(data)
            count = str(len(py_value)) if self.conv_func is str else ''
            return struct.pack(self.BSA+count+self.fmt_chr, py_value)
    
    type_conv = {'string': TypeConv(str, 's'),
                 'int32': TypeConv(int, 'i'),
                 'int64': TypeConv(long, 'q'),
                 'float32': TypeConv(float, 'f'),
                }
    
    array = [['string', 'int32', 'string', 'int64', 'float32', 'string', 'string'],
             ['any string', '19', 'any string', '198732132451654654',
              '0.6', 'any string', 'any string']]
    
    binary_values = [type_conv[type_id].pack(data)
                         for type_id, data in zip(array[0], array[1])
                             if type_id in type_conv]  # to skip any unknown type_ids
    print binary_values
    

    输出:

    ['any string', '\x13\x00\x00\x00', 'any string', '\xfe\x9b<P\xd2\t\xc2\x02',
     '\x9a\x99\x19?', 'any string', 'any string']
    

    TypeConv.pack() 方法首先将字符串值转换为其等效的 Python 值 py_value,然后使用 struct.pack() 将其转换为 C 二进制值——我认为这正是您所寻求的。

    【讨论】:

      【解决方案3】:

      我不确定这是否正是您想要的,但我认为这就是您要寻找的:

      casts = { 'string': lambda x: str(x), \
          'int32': lambda x: int(x), \
          'int64': lambda x: int(x), \
          'float32': lambda x: float(x) }
      
      types_to_cast = [['string','int32','string','int64','float32','string','string'],['any string','19','any string','198732132451654654','0.6','any string','any string']]
      
      print [casts[types_to_cast[0][i]](types_to_cast[1][i]) for i in range(len(types_to_cast[0]))]
      

      【讨论】:

      • lambda 字典中的 lambda 函数的额外开销是不必要的,因为它们所做的只是调用另一个函数。 FWIW 我通常发现,每当我发现自己使用 for i in range(...) 时认为它是一个信号,即很可能有一种更“Pythonic”——而且可能更短、更易读——的方法来做同样的事情。跨度>
      • 谢谢您的建议。
      猜你喜欢
      • 2019-03-06
      • 2018-09-24
      • 2012-11-13
      • 2015-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-16
      • 1970-01-01
      相关资源
      最近更新 更多