Серийно-эффективный (де) сериализованный массив экземпляров 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)
Другие вопросы по тегам