2013-05-29 4 views
3

Я хотел бы узнать, есть ли более чистый способ сделать следующее в Python 2.7?Python - распаковать структуру на несколько кортежей

# 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) 

ответ

6

Вы можете сделать это одним вызовом 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 
+0

Хороший ход с 'iter (data)' – alexis

+0

@unutbu Отлично. Спасибо за быстрый ответ! – Daniel

1

Я отлажены @ unutbu ответим на бит с помощью unpack_from со смещением вместо распаковки с помощью срезов.

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)) 
+0

Выполняется немного медленнее на IPython, но быстрее для стандартного python 2.7 для меня. – Daniel