分享

如何获取numpy数组的真实地址?如何与ctypes数组共享内存?

 lgk88888 2020-12-01

1、如何获取numpy数组元素的真实地址?

在Python编程中,numpy是一个很好用的扩展程序库,将其与SciPy库和 Matplotlib绘图库一起使用,可构成一个强大的类似于Matlab的科学计算环境,有助于我们通过 Python 学习数据科学或者机器学习。在Python中,当你定义了一个numpy类型的数组后,它内部元素的真实地址如何获得呢?

  

这里可以通过numpy数组的“__array_interface__”接口得到。

比如下面的例子:

import numpy as np 

from ctypes import * 

a = np.array([1, 2, 3, 4, 5], dtype=np.uint8) 

print(a.__array_interface__['data'])

上面程序定义了一个numpy类型的数组a,运行后得到:

(1883707159072, False)

接口__array_interface__”返回一个包含两个元素的元组,其第1个元素即为a数组内部元素存放的真实地址,第2个元素标明了该数组是否为“只读”属性。

2、如何与ctypes库创建的数组共享内存空间?

对于Python编程人员来说,ctypes库也是使用率比较高的一个库,当调用第三方提供的动态库链接库函数时,它经常用于定义与C语言兼容的数据类型变量,作为Python语言与C语言进行数据交互的桥梁。

那么,如何使用ctypes库定义一个与numpy共享内存空间的数组变量呢?

仍以上面的例子,定义一个uint8类型的数组b,与a数组共享内存区域,可使用下面的代码:

b = (c_uint8*len(a)).from_address(a.__array_interface__['data'][0]) 

print('a =', a, '\nb =', b[:])

运行后得到:

a = [1 2 3 4 5] 

b = [1, 2, 3, 4, 5]

可见,使用ctypes库的from_address函数定义了一个与a同地址的数组b,打印出b的元素值后,其初始元素值确实与数组a相同。

下面验证一下,数组a和b里面的元素是否真正的占用同一个内存区域。

先改变数组a中第1个元素的值,运行下面的代码:

a[0] = 10 

print('a =', a, '\nb =', b[:]}])

其运行结果为:

a = [10 2 3 4 5] 

b = [10, 2, 3, 4, 5]

可见,将数组a中的第一个元素的值由1改成10后,b数组中第一个元素也同步改变成10了。

紧接着,再改变b数组中第二个元素的值,由2改为20:

b[1] = 20 

print('a =', a, '\nb =', b[:])

其运行结果为:

a = [10 20 3 4 5] 

b = [10, 20, 3, 4, 5]

显然,数组a中第二个元素的值也同步改变为20了。

因此,数组a与数组b确实是占用的同一个内存地址空间。

另外,也可以通过数组b再定义一个与b共享内存区域的numpy数组c,使用下面的代码即可:

c = np.frombuffer(b, dtype=np.uint8)

大家可以自行验证数组a、b、c是否为同一个内存空间。

3、结论

上面的例子表明,在Python编程中,numpy类型的数组与ctypes类型的数组可以进行互换,比如,可以使用numpy库进行复杂的运算后,再转换成ctypes类型的数组,传递到第3方的动态库dll函数中作进一步的处理,这样,在某些场合下,既能使用numpy库的强大运算功能,又可以使用第三方库,来实现我们特定的处理需求。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多