01如何獲取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個元素標明了該數組是否為「只讀」屬性。
02如何與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是否為同一個內存空間。
03結論
上面的例子表明,在Python編程中,numpy類型的數組與ctypes類型的數組可以進行互換,比如,可以使用numpy庫進行複雜的運算後,再轉換成ctypes類型的數組,傳遞到第3方的動態庫dll函數中作進一步的處理,這樣,在某些場合下,既能使用numpy庫的強大運算功能,又可以使用第三方庫,來實現我們特定的處理需求。
本文由編碼那些事原創,歡迎關注+轉發+收藏+點讚,帶你一起長知識!