Как написать длинное целое как двоичное в Python?

В Python длинные целые числа имеют неограниченную точность. Я хотел бы написать целое число в 16 байт (128 бит) в файл. struct из стандартной библиотеки поддерживает только до 8 байтовых целых чисел. array имеет такое же ограничение. Есть ли способ сделать это без маскировки и смещения каждого целого?

Некоторые пояснения здесь: я пишу в файл, который будет читаться из программ, отличных от Python, так что рассол отсутствует. Все 128 бит используются.

8 ответов

Два возможных решения:

  • Просто pickle ваше длинное целое число. Это будет записывать целое число в специальном формате, который позволяет его читать снова, если это все, что вы хотите.

  • Используйте второй фрагмент кода в этом ответе, чтобы преобразовать длинный int в большую строку endian (которую можно легко изменить на маленький endian, если вы предпочитаете), и напишите эту строку в ваш файл.

Проблема заключается в том, что внутреннее представление bigints не содержит непосредственно двоичные данные, которые вы запрашиваете.


Я думаю, что для целых чисел без знака (и игнорирования сущности) что-то вроде

import binascii
def binify(x):
 h = hex(x)[2:].rstrip('L')
 return binascii.unhexlify('0'*(32-len(h))+h)
>>> for i in 0, 1, 2**128-1:
... print i, repr(binify(i))
... 
0 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
340282366920938463463374607431768211455 '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'

может технически удовлетворять требованиям наличия не-Python-специфического вывода, не используя явную маску, и (я предполагаю) не использовать какие-либо нестандартные модули. Не особенно элегантно, тем не менее.


Почему бы не использовать struct с unsigned long long type дважды?

import struct
some_file.write(struct.pack("QQ", var/(2**64), var%(2**64)))

Это описано здесь (прокрутите вниз, чтобы получить таблицу с Q): http://docs.python.org/library/struct.html


Модуль PyPi bitarray в сочетании со встроенной функцией bin() кажется хорошей комбинацией для простого и гибкого решения.

bytes = bitarray(bin(my_long)).tostring()

Индийность может контролироваться еще несколькими строками кода. Вы должны будете оценить эффективность.


Это может не избежать требования "маска и сдвиг каждого целого". Я не уверен, что избегать использования маски и сдвига в контексте длинных значений Python.

Эти байты:

def bytes( long_int ):
 bytes = []
 while long_int != 0:
 b = long_int%256
 bytes.insert( 0, b )
 long_int //= 256
 return bytes

Затем вы можете упаковать этот список байтов с помощью struct.pack( '16b', bytes )


Это может быть немного поздно, но я не понимаю, почему вы не можете использовать struct:

bigint = 0xFEDCBA9876543210FEDCBA9876543210L
print bigint,hex(bigint).upper()
cbi = struct.pack("!QQ",bigint&0xFFFFFFFFFFFFFFFF,(bigint>>64)&0xFFFFFFFFFFFFFFFF)
print len(cbi)

bigint сам по себе отклоняется, но если вы замаскируете его с помощью & 0xFFFFFFFFFFFFFFFF, вы можете уменьшить его до 8 байтов int вместо 16. Затем верхняя часть сдвигается и маскируется. Возможно, вам придется немного поиграть с байтом. Я использовал! чтобы сообщить ему, чтобы создать порядковый байтовый адрес сети. Кроме того, возможно, потребуется изменить значение msb и lsb (верхний и нижний байты). Я оставлю это как упражнение для определения пользователем. Я бы сказал, экономя вещи, поскольку сетевой endian будет более безопасным, поэтому вы всегда знаете, что такое endianess ваших данных.

Нет, не спрашивайте меня, если сетевой endian большой или маленький endian...


Вы можете разделить объект на двоичный, использовать буферы протокола (я не знаю, разрешают ли они вам сериализовать неограниченные целые числа точности) или BSON, если вы не хотите писать код.

Но написать функцию, которая выгружает 16 байтовых целых чисел, сдвигая ее, не стоит так тяжело делать, если это не критическое время.


С Python 3.2 и более поздними версиями вы можете использовать int.to_bytes и int.from_bytes: https://docs.python.org/3/library/stdtypes.html#int.to_bytes

licensed under cc by-sa 3.0 with attribution.