Серийно-эффективный (де) сериализованный массив экземпляров MyClass
Мой объект выглядит так:
class Note(object):
def __init__(self, note, vel, t, tOff=0):
self.note = note # ubyte
self.vel = vel # ubyte
self.t = t # float
self.tOff = tOff # float
(Указания типа показывают точность, требуемую для каждого поля, а не то, как Python фактически хранит их!)
Моя программа создает массив из нескольких тысяч Note-ов.
Мне нужно преобразовать этот массив в строку, чтобы я мог AJAX-файл на сервере для хранения (и впоследствии получить и преобразовать обратно в исходную структуру данных).
Я использую Brython, который реализует библиотеку JSON Python (я тестировал: import json
работает. Поэтому я подозреваю, что JSON - моя лучшая ставка.
Но Brython не является полной реализацией CPython, поэтому я, вероятно, не могу импортировать неосновные библиотеки. И похоже, что я не могу сделать что-то необычное, например, использовать слоты для класса с эффективным хранением. (Brython отображает конструкции Python на соответствующие конструкции JavaScript).
Теоретически, я должен иметь возможность уменьшить каждую ноту до 10 байт, но я стремлюсь к тому, чтобы бережливый код предлагал достаточно компактное хранилище, а не максимальную компактность. Однако я хотел бы избежать огромной неэффективности, такой как хранение каждой ноты в виде пары ключ-значение - т.е. ключи будут дублироваться.
Если бы я мог видеть диапазон доступных мне решений, я мог бы выбрать подходящий компромисс между сложностью и компактностью. То есть я был бы благодарен за ответ в любом месте континуума.
1 ответ
Быстрый тест с использованием struct
кажется, дает вам возможную длину 12 байтов следующим образом:
import struct
class Note(object):
def __init__(self, note, vel, t, tOff=0):
self.note = note # ubyte
self.vel = vel # ubyte
self.t = t # float
self.tOff = tOff # float
def pack(self):
return struct.pack("BBff", self.note, self.vel, self.t, self.tOff)
def unpack(self, packed):
self.note, self.vel, self.t, self.tOff = struct.unpack("BBff", packed)
note = Note(10, 250, 2.9394286605624826e+32, 1.46971433028e+32)
packed = note.pack()
print "Packed length:", len(packed)
note2 = Note(0,0,0)
note2.unpack(packed)
print note2.note, note2.vel, note2.t, note2.tOff
Это отображает:
Packed length: 12
10 250 2.93942866056e+32 1.46971433028e+32
Возможно, вы сможете дополнительно сжать его в зависимости от типа поплавков, которые вам нужны, т.е. возможна ли какая-то фиксированная точка?
Чтобы упаковать список notes
можно использовать что-то вроде следующего:
notes = [1,2,3,4,5,6,7,8,9,10]
print struct.pack("{}B".format(len(notes)), *notes)
Но распаковка должна быть такой же длины. Или вы можете добавить байт длины для распаковки:
notes = [1,2,3,4,5,6,7,8,9,10]
packed = struct.pack("B{}B".format(len(notes)), len(notes), *notes)
length = struct.unpack("B", packed[0])[0]
print struct.unpack("{}B".format(length), packed[1:])
Это будет отображать правильно распакованные данные:
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)