Преобразование массив байтов с переменным размером в целое / длинное

Как я могу преобразовать двоичный байтовый массив с переменным размером (big endian) в целое число (без знака) / long? В качестве примера, '\x11\x34' , который представляет 4404

Прямо сейчас, я использую

  • Преобразование PIL изображения в массив байтов?
  • Преобразование python long / int в массив байтов фиксированного размера
  • Как разбить строку байта на отдельные байты в python
  • 'str' не поддерживает буферный интерфейс Python3 из Python2
  • PIL: преобразовать Bytearray в изображение
  • Как преобразовать мой bytearray ('b \ x9e \ x18K \ x9a') в нечто подобное -> '\ x9e \ x18K \ x9a' <--- просто str, а не массив
  •  def bytes_to_int(bytes): return int(bytes.encode('hex'), 16) 

    Это маленький и несколько читаемый, но, вероятно, не очень эффективный. Есть ли лучший (более очевидный) способ?

  • Как проверить, есть ли каждый элемент в списке типа 'int'?
  • Почему в Python требуется в три раза больше памяти?
  • Как разбить строку байта на отдельные байты в python
  • Как преобразовать мой bytearray ('b \ x9e \ x18K \ x9a') в нечто подобное -> '\ x9e \ x18K \ x9a' <--- просто str, а не массив
  • Преобразование строк списка в список целых чисел внутри списка
  • Неподдерживаемый тип (ы) операндов для +: 'int' и 'str'
  • 2 Solutions collect form web for “Преобразование массив байтов с переменным размером в целое / длинное”

    Python традиционно не имеет большого значения для «чисел в макете большого конца», которые слишком велики для C. (Если вы имеете дело с 2-байтными, 4- struct.unpack или 8-байтовыми числами, тогда struct.unpack это ответ.)

    Но достаточно людей стало тошнить от того, что не было одного очевидного способа сделать это, чтобы Python 3.2 добавил метод int.from_bytes который делает именно то, что вы хотите:

     int.from_bytes(b, byteorder='big', signed=False) 

    К сожалению, если вы используете более старую версию Python, у вас ее нет. Итак, какие у вас варианты? (Помимо очевидного: обновление до 3.2, или, лучше, 3.4 …)


    Во-первых, есть ваш код. Я думаю, что binascii.hexlify – лучший способ записать его, чем .encode('hex') , потому что «encode» всегда казался немного странным для метода по байтовым строкам (в отличие от строк Unicode), и на самом деле это было изгнанный на Python 3. Но в остальном это кажется мне довольно понятным и очевидным. И он должен быть довольно быстрым – да, он должен создать промежуточную строку, но он выполняет всю петлю и арифметику в C (по крайней мере, в CPython), что, как правило, на порядок или два быстрее, чем в Python. Если ваш bytearray настолько велик, что выделение строки само по себе будет дорогостоящим, я бы не стал беспокоиться о производительности здесь.

    В качестве альтернативы вы можете сделать это в цикле. Но это будет более многословным и, по крайней мере, в CPython, намного медленнее.

    Вы можете попытаться устранить явный цикл для неявного, но очевидная функция для этого – reduce , которое считается частью не-Pythonic частью сообщества, и, конечно же, потребуется вызвать функцию для каждого байта.

    Вы можете развернуть цикл или reduce его, разбив его на куски 8 байтов и struct.unpack_from через struct.unpack_from или просто сделав большой struct.unpack('Q'*len(b)//8 + 'B' * len(b)%8) и зацикливается на этом, но это делает его намного менее читаемым и, вероятно, не намного быстрее.

    Вы можете использовать NumPy … но если вы собираетесь больше 64 или, может быть, 128 бит, это все равно приведет к конвертации всего в объекты Python.

    Итак, я думаю, что ваш ответ – лучший вариант.


    Вот некоторые моменты, сравнивающие его с наиболее очевидным ручным преобразованием:

     import binascii import functools import numpy as np def hexint(b): return int(binascii.hexlify(b), 16) def loop1(b): def f(x, y): return (x<<8)|y return functools.reduce(f, b, 0) def loop2(b): x = 0 for c in b: x <<= 8 x |= c return x def numpily(b): n = np.array(list(b)) p = 1 << np.arange(len(b)-1, -1, -1, dtype=object) return np.sum(n * p) 

     In [226]: b = bytearray(range(256)) In [227]: %timeit hexint(b) 1000000 loops, best of 3: 1.8 µs per loop In [228]: %timeit loop1(b) 10000 loops, best of 3: 57.7 µs per loop In [229]: %timeit loop2(b) 10000 loops, best of 3: 46.4 µs per loop In [283]: %timeit numpily(b) 10000 loops, best of 3: 88.5 µs per loop 

    Для сравнения в Python 3.4:

     In [17]: %timeit hexint(b) 1000000 loops, best of 3: 1.69 µs per loop In [17]: %timeit int.from_bytes(b, byteorder='big', signed=False) 1000000 loops, best of 3: 1.42 µs per loop 

    Итак, ваш метод все еще довольно быстрый …

    Функция struct.unpack (…) делает то, что вам нужно.

    Python - лучший язык программирования в мире.