Запись списка кортежей (int, float) в поток без преобразования в строку - PullRequest
0 голосов
/ 05 марта 2019

У меня есть список в Python, который состоит из кортежей, которые имеют следующий формат: (int, float). Я хочу записать этот список в поток байтов io или io без необходимости конвертировать целые числа и / или числа с плавающей запятой в строку. Как я могу это сделать? Спасибо.

Ответы [ 2 ]

1 голос
/ 06 марта 2019

Существует множество форматов, которые можно использовать для сериализации объектов Python в байты.Есть плюсы и минусы для каждого из них.

Если в данных имеется только список кортежей целых и дробных чисел, что делает работу довольно простой.

Предположим, это данные:

data = 100 * [(1, 1.111), (18, 1.234), (555555, 0.001), (-1, 1e70)]

Какая из них попадает в категорию «струн», мне не ясно.Наиболее очевидный формат «строки» будет str(data).Насколько он велик?

>>> len(str(data))
5500

Это занимает 5500 байт.Вопрос требует чего-то более сжатого.Итак, мы ищем что-то намного короче, чем 5500 байт.

JSON - очень популярный формат (это также строка).Насколько он велик?

>>> len(json.dumps(data))
5500

Он имеет такой же размер (5500 байт), но, по крайней мере, он четко определен.Это может быть меньше?Как насчет BZipped JSON ?

>>> len(bz2.compress(json.dumps(data).encode('utf-8')))
131

Это намного лучше!

Это, вероятно, было очень хорошо из-за повторяющегося паттерна.Есть ли формат, в котором не используется архивирование?Возможно рассол ?

>>> len(pickle.dumps(data))
862

Не так хорошо, как почтовый индекс (конечно!), Но все же хорошо.

Можем ли мы сделать BZipped рассол ?

>>> len(bz2.compress(pickle.dumps(data)))
155

Лучше, но нет оснований для того, чтобы он был лучше, чем BZipped JSON.

Как насчет другого формата?Вы можете преобразовать каждый кортеж в эквивалент этой структуры C , используя модуль struct :

struct {
    int i;
    double f;
};

Однако тогда вам придется знать, насколько великаINT может быть.Python int может быть настолько большим, насколько вы хотите, но если вы, например, знаете, что все числа находятся в диапазоне от 0 до 255, вам просто нужен один байт.Для float вам нужно 64 бита (т.е. 8 байт), иначе вы потеряете точность.Таким образом, это увеличится до 1000 байтов.Не очень хорошо.

Есть и другие встроенные опции, документированные в Документация Python по сохранению .

Вы также можете придумать свой собственный формат.

В конце концов, вы должны решить, что подходит вам больше всего.

0 голосов
/ 06 марта 2019

Вы можете легко и просто вывести целые числа и числа с плавающей точкой в ​​байты, используя struct module .

>>> import struct
>>> data = [(2, 1.0), (3, 2.0), (25, 55.5)]
>>> for tup in data:
    bytes_data = struct.pack("<ld", *tup)
    print(bytes_data)


b'\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?'
b'\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@'
b'\x19\x00\x00\x00\x00\x00\x00\x00\x00\xc0K@'

В качестве строки, которую я использую в качестве первого аргумента функции pack, используется идентификатор формата, который сообщает вам, какой тип и размер каждого числа, в данном случае l является длиннымсо знаком int d является двойным числом

...