I'd like to know if there is a cleaner way to do the following in 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)
Specifically, I don't like manually keeping track of the offset into the next tuple. Ideally I'd like to be able to specify the data structure with a single format statement; Something like this:
# Hypothetical example, does not work!
(is_enabled,), cmd_speed, tach_speed = struct.unpack("<(?),(3h),(3h)", data)
You could do it with one call to struct.unpack
, but you'd still have to slice up the result yourself:
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)
yields
(True, (1, 2, 3), (4, 5, 6))
Or, you could use this:
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)
which yields
(True, (1, 2, 3), (4, 5, 6))
Although unpack_formats
looks prettier, the following is actually faster (probably because there is no ''.join
needed):
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
I tweaked @unutbu's answer a bit by using unpack_from with an offset instead of unpack with slices.
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))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With