__array_interface__ 是 numpy 数组暴露的描述底层内存布局的字典接口,支持零拷贝共享内存的前提是双方理解一致且数组内存为c连续、可写、未被gc回收;它本身不传输数据,仅提供内存访问元信息。

什么是 __array_interface__?它真能零拷贝共享内存?
__array_interface__ 是 NumPy 数组对象暴露的一个字典接口,用于描述其底层内存布局(如数据地址、形状、数据类型、步长等)。其他支持该协议的库(如 PyTorch、Cython、Pillow、某些 C 扩展)可通过读取这个字典直接访问 NumPy 数组的内存,**避免复制**——但前提是双方对内存布局的理解一致,且内存是 C 连续、非只读、未被 Python 垃圾回收管理的。
关键点:它本身不传输数据,只是“告诉别人怎么读我的内存”。是否真能零拷贝,取决于对方库是否正确实现解析逻辑,以及 NumPy 数组是否满足可共享条件(比如不能是 np.array([1,2,3], dtype=object),也不能是 view 且 base 已释放)。
如何安全导出 __array_interface__ 并被其他库消费?
直接读取 a.__array_interface__ 即可,但必须检查几个关键字段:
-
data:二元组(address, is_writable),address 是整数地址,不是 bytes 或 buffer 对象;若is_writable == False,下游写入会出错或未定义 -
shape和strides:决定内存如何索引;若strides为None,表示 C 连续,否则需按步长解析 -
typestr:如'<f8>(小端 float64),必须与下游期望类型匹配;<code>'|b1'(bool)在某些库中不被支持 -
version:应为 3;旧版本(如 2)缺少mask等字段,兼容性差
示例:
>>> a = np.arange(4, dtype=np.float32).reshape(2, 2)
>>> a.__array_interface__
{'version': 3,
'shape': (2, 2),
'typestr': '<f4 true none>注意:<code>data[0]</code> 是地址,不可直接传给 ctypes.cast() 而不转为 <code>c_void_p</code>。
<h3>为什么 PyTorch 或 PIL 有时拒绝接受 <code>__array_interface__</code>?</h3>
<p>常见失败原因不是协议本身无效,而是下游库做了额外校验或限制:</p>
<ul>
<li>PyTorch 的 <code>torch.from_numpy()</code> 内部用的是 <code>__array__()</code>,不是直接读 <code>__array_interface__</code>;若手动构造 tensor,需确保 <code>strides</code> 符合其内存模型(PyTorch 只支持 C/F 连续,不支持任意 strides)</li>
<li>PIL.Image.fromarray() 接受 NumPy 数组,但会检查 <code>dtype</code> 是否在白名单内(如 <code>uint8</code>, <code>float32</code>),即使 <code>__array_interface__</code> 正确,<code>typestr</code> 为 <code>'<i4>(int32)也会被拒</i4></code>
</li>
<li>某些 Cython 模块硬编码要求 <code>strides == None</code>,遇到跨步数组(如 <code>a[::2]</code>)就报错,而非尝试解析 <code>strides</code>
</li>
<li>NumPy 数组若由 <code>np.frombuffer()</code> 创建且 buffer 来自临时 bytes,<code>data</code> 地址可能在后续被回收,导致悬垂指针</li>
</ul>
<h3>替代方案:什么时候该放弃 <code>__array_interface__</code>?</h3>
<p>当目标库不实现该协议,或你无法控制其解析逻辑时,以下方式更可靠:</p>
<ul>
<li>用 <code>np.ascontiguousarray()</code> 强制 C 连续 + <code>.data.ptr</code> 获取 <code>c_void_p</code>,配合 ctypes 或 CFFI 直接传地址(比解析 <code>__array_interface__</code> 更底层、更可控)</li>
<li>对 PyTorch:优先走 <code>torch.from_numpy()</code> 或 <code>torch.tensor(..., copy=False)</code>,它们内部已处理好所有权和内存生命周期</li>
<li>对 OpenCV:用 <code>cv2.cvtColor(np_array, ...)</code> 自动适配,不要自己解析 <code>__array_interface__</code>;OpenCV 的 Mat 构造函数接受 data ptr,但需手动指定 rows/cols/type,容易错配 <code>typestr</code> 和 OpenCV 的 <code>CV_32F</code> 等常量</li>
</ul>
<p>真正棘手的从来不是怎么导出接口,而是谁持有内存、何时释放、是否对齐、是否允许写入——这些细节全藏在 <code>__array_interface__</code> 字段里,但没人替你做交叉验证。</p></f4>Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











