你可以利用
ctypes
模块创建一个指向数据数组的指针,并将其转换为字节形式。
import ctypes
import numpy as np
size = 0x10
dtype = np.short
bsize = 2
arr = np.arange(size, dtype=dtype)
memory_block = (ctypes.c_char*(size*bsize)).from_address(arr.ctypes.data)
print(memory_block.raw)
arr[0] = 255.
print(memory_block.raw)
至少从评论中提出的问题来看,这似乎是满足测试要求的。(即如果我改变数组会不会改变我的视图?)。
但是需要注意几点。首先,Python 字节对象是不可变的,这意味着如果将其分配给一个变量,会生成一份副本。
y = memory_block.raw
print(y[:2])
arr[0] = 127
print(y[:2])
两个,boto3
似乎需要一个类似文件的对象,至少根据版本 1.28.1 的源代码是这样的。调用 bio = BytesIO(memory_block.raw)
会产生一次复制,这意味着我们又回到了上传的起点。
一个上传器类
下面的 ArrayUploader
类实现了一些基本的 IO 方法(read
、seek
、tell
)。当调用 read
时,数据可能仍然会从底层内存块复制,这意味着头部空间仍然是限制因素。然而,如果设置读取大小,那么只有这么多数据会从内存块中一次性复制出来。我无法告诉你 boto3
如何处理从 IO
对象读取的大小。
import ctypes
import re
from io import IOBase
import numpy as np
class ArrayUploader(IOBase):
def __init__(self, array):
dbits = re.search('\d+', str(np.dtype(array.dtype))).group(0)
dbytes = int(dbits) // 8
self.nbytes = array.size * dbytes
self.bufferview = (ctypes.c_char*(self.nbytes)).from_address(array.ctypes.data)
self._pos = 0
def tell(self):
return self._pos
def seek(self, pos):
self._pos = pos
def read(self, size=-1):
if size == -1:
return self.bufferview.raw[self._pos:]
old = self._pos
self._pos += size
return self.bufferview.raw[old:self._pos]
size = 0x10
dtype = np.short
arr = np.arange(size, dtype=dtype)
arrayuploader = ArrayUploader(arr)
print(x:=arrayuploader.read(8))
arr[0] = 127
arrayuploader.seek(0)
print(y:=arrayuploader.read(8))
print(x == y)
arr[0]=something else
来检查,然后再检查缓冲区是否发生变化。我也不想涉及磁盘I/O :) - franklsf95