【问题标题】:Python - unpack struct into multiple tuplesPython - 将结构解压成多个元组
【发布时间】:2013-05-29 20:56:42
【问题描述】:

我想知道在 Python 2.7 中是否有更简洁的方法来执行以下操作?

# Current working code!
(is_enabled,) = struct.unpack_from("<?", data)
cmd_speed = struct.unpack_from("<3h", data, 1)
tach_speed = struct.unpack_from("<3h", data, 1+2*3)

具体来说,我不喜欢手动跟踪下一个元组的偏移量。 理想情况下,我希望能够使用单个格式语句指定数据结构;像这样的:

# Hypothetical example, does not work! 
(is_enabled,), cmd_speed, tach_speed = struct.unpack("<(?),(3h),(3h)", data)

【问题讨论】:

    标签: python tuples iterable-unpacking


    【解决方案1】:

    您可以通过一次调用 struct.unpack 来完成,但您仍然需要自己分割结果:

    import struct
    data = struct.pack('<?3h3h', True, 1,2,3,4,5,6)
    result = struct.unpack('<?3h3h', data)
    is_enabled = result[0]
    cmd_speed = result[1:4]
    tach_speed = result[4:7]
    
    print(is_enabled, cmd_speed, tach_speed)
    

    产量

    (True, (1, 2, 3), (4, 5, 6))
    

    或者,你可以使用这个:

    import struct
    import itertools as IT
    
    def unpack_formats(fmts, data):
        data = iter(data)
        return [struct.unpack(fmt, ''.join(IT.islice(data, struct.calcsize(fmt))))
                for fmt in fmts]
    
    data = struct.pack('<?3h3h', True, 1,2,3,4,5,6)
    fmts = ('<?', '<3h', '<3h')
    (is_enabled,), cmd_speed, tach_speed = unpack_formats(fmts, data)
    print(is_enabled, cmd_speed, tach_speed)
    

    产生

    (True, (1, 2, 3), (4, 5, 6))
    

    虽然unpack_formats看起来更漂亮,但下面的实际上更快(可能是因为不需要''.join):

    def unpack_formats2(fmts, data):
        result = []
        i = 0
        for fmt in fmts:
            size = struct.calcsize(fmt)
            j = i+size
            result.append(struct.unpack(fmt, data[i:j]))
            i = j
        return result
    
    In [80]: %timeit unpack_formats(fmts, data)
    100000 loops, best of 3: 3.51 us per loop
    
    In [81]: %timeit unpack_formats2(fmts, data)
    1000000 loops, best of 3: 1.61 us per loop
    

    【讨论】:

    • iter(data) 的好举动
    • @unutbu 非常好。感谢您的快速回复!
    【解决方案2】:

    我通过使用带有偏移量的 unpack_from 而不是使用切片解包来稍微调整了@unutbu 的答案。

    def unpack_formats3(fmts, data):
        result = []
        offset = 0
        for fmt in fmts:
            result.append(struct.unpack_from(fmt, data, offset))
            offset += struct.calcsize(fmt)
        return result
    
    data = struct.pack('<?3h3h', True, 1,2,3,4,5,6)
    fmts = ('<?', '<3h', '<3h')
    (is_enabled,), cmd_speed, tach_speed = unpack_formats3(fmts, data)
    
    print(is_enabled, cmd_speed, tach_speed)
    (True, (1, 2, 3), (4, 5, 6))
    

    【讨论】:

    • 在 IPython 上运行有点慢,但对我来说在标准 python 2.7 上运行得更快。
    猜你喜欢
    • 1970-01-01
    • 2015-05-08
    • 2016-11-12
    • 1970-01-01
    • 2010-10-13
    • 2016-04-12
    • 2022-01-21
    • 1970-01-01
    • 2021-10-07
    相关资源
    最近更新 更多