2016-08-13 1 views
4

В Python 3 можно интерпретировать основную память как массив байтов или Интс или тоскует через memoryview.cast():Интерпретируя ByteArray как массив длинных позиций в Python 2.7

[] b=bytearray(2*8) 
[] b 
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 
[] m=memoryview(b).cast('L') #reinterpret as an array of unsigned longs 
[] m[1]=2**64-1 
[] b 
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff') 

Как можно видеть, мы можем обращайтесь к bytearrayb, как будто он содержит массив беззнаковых длин (длиной 8 байт на моей машине) с помощью memoryviewm.

Однако в Python 2.7 memoryviewlacks метод cast.

Таким образом, мой вопрос: есть ли возможность переинтерпретировать bytearray как массив longs в Python 2.7?

Важно сделать это, не копируя и не выделяя больше памяти.

Времени, необходимое для чтения длинного значения с помощью T[i] на моей машине (Python 3.4):

python list:    40ns (fastest but needs 24 bytes per element) 
python array:    120ns (has to create python int-object) 
memoryview of bytearray 120ns (the same as array.array) 
Jean-François's solution: 6630ns (ca. 50 times slower) 
Ross's solution:   120ns 

ответ

1

Вы можете использовать ctypes и его метод from_buffer создать ctypes массив беззнаковых длинных позиций, что делится своей памятью с объектом bytearray.

Например:

import ctypes 

ba = bytearray(b'\x00' * 16) 
a = (ctypes.c_ulong * (len(ba)/8)).from_buffer(ba) 
a[1] = -1 
print repr(ba) 
1

Не совсем переосмысление, так как он создает копию. В этом случае вам придется

  • конвертировать bytearray в список длинных позиций
  • работы со списком тоскует
  • преобразовывают обратно bytearray, когда вы сделали

(немного например, с использованием символов str при их преобразовании в список символов, их изменение, затем их объединение обратно в строку)

import struct 

b=bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff') 

larray=[] 

for i in range(0,len(b),8): 
    larray.append(struct.unpack('@q',b[i:i+8])[0]) 

print(larray) 

larray[1]=1000 

b = bytearray() 

for l in larray: 
    b += struct.pack('@q',l) 

print(b) 

Метод, который не включает в себя копию (работает только для длинных целых чисел):

def set_long(array,index,value): 
    index *= 8 

    if sys.byteorder=="little": 
     shift=0 
     for i in range(index,index+8): 
      array[i] = (value>>shift) & 0xFF 
      shift += 8 
    else: # sys.byteorder=="big" 
     shift = 56 
     for i in range(index+8,index,-1): 
      array[i] = (value<<shift) & 0xFF 
      shift -= 8 

def get_long(array,index): 
    index *= 8 
    value = 0 

    if sys.byteorder=="little": 
     shift=0 
     for i in range(index,index+8): 
      c = (array[i]<<shift) 
      value += c 
      shift += 8 
    else: # sys.byteorder=="big" 
     shift = 56 
     for i in range(index+8,index,-1): 
      value += (array[i]>>shift) 
      shift -= 8 

    return value 

b=bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff')  
print(get_long(b,1)==2**64-1) 
set_long(b,1,2001) 
print(b) 

print(get_long(b,1)) 

выход:

bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x03\x00\x00\x00\x00\x00\x00') 
True 
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x07\x00\x00\x00\x00\x00\x00') 
2001 
+0

К сожалению, я не был достаточно четко в моем вопросе, все дело в том, чтобы сделать это без дополнительной памяти. – ead

+0

Не проблема, я ждал, чтобы играть с 'pack' некоторое время. Я думаю, что позже придумаю свое решение. –

+0

добавлен метод. Не супер slick, но работает с python 2 –