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