在 Python 2.7 中将字节数组解释为长整数数组

Interpreting a bytearray as array of longs in Python 2.7

在 Python 3 中,可以通过 memoryview.cast():

将底层内存解释为字节数组或整数或长整数
[] 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')

可以看出,我们可以访问 bytearray b 就好像它是一个无符号长数组(在我的机器上是 8 字节长)借助 memoryview m.

但是,在Python 2.7 memoryview lacks 方法中cast

因此我的问题是:是否有可能将 bytearray 重新解释为 Python 2.7 中的多头数组?

在没有 copying/allocating 更多内存的情况下执行此操作很重要。

在我的机器上通过 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

不是真正的重新解释,因为它创建了一个副本。在这种情况下,您必须

  • 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)

不涉及复制的方法(只适用于long ints):

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

您可以使用 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)