1 回答

TA貢獻1813條經驗 獲得超2個贊
您可以將您的 Go 代碼與 Python 代碼掛鉤,但要使其能夠從 Python 訪問,您必須//export使用 Go 函數。
您不能將切片直接傳遞給 Go 代碼。您必須使用 Go 數組將其偽裝出來,使用從 C 或 Python 代碼調用的導出函數中的轉換添加切片標頭。 peterSO對相關問題Accessing C array in golang的回答展示了如何使用unsafe.Pointer(盡管 forint而不是float64)來做到這一點。我有點懷疑這里的硬編碼數組大小會在未來的一些 Go 實現中中斷,但它今天確實有效。(這里的 C 數組也可能有 8 GB 的大小限制。)
因此(現在測試):
package main
import "C"
import (
"fmt"
"unsafe"
)
//export CTestArray
func CTestArray(xsBase *C.double, n C.int) {
xs := (*[1 << 30]float64)(unsafe.Pointer(xsBase))[:n:n]
testArray(xs)
}
func testArray(xs []float64) {
for _, arg := range xs {
fmt.Println(arg)
}
}
func main() {}
(從技術上講,您不需要中間函數:testArray代碼可以在創建切片變量后出現。但我建議使用包裝器構造,以便您的 Go-only 代碼不使用unsafe:所有潛在的可怕錯誤都局限于包裝器.)
剩下的棘手部分是在 Python 中構建數組并傳遞它。您必須對實際大小進行編碼。幸運的是,繼續重置似乎沒問題argtypes:
from ctypes import *
lib = cdll.LoadLibrary("./main.so")
print ("Loaded go generated SO library")
lib.CTestArray.restype = None
l = [1, 3, .5, 2, 1, 1, 2, 3, .5, 3, 1, 1, 3, 1, 1, 3, 2, 1]
arr = (c_double * len(l))(*l)
lib.CTestArray.argtypes = [type(arr), c_int]
lib.CTestArray(arr, len(arr))
print("done 1")
l = [42, 3.1415]
arr = (c_double * len(l))(*l)
lib.CTestArray.argtypes = [type(arr), c_int]
lib.CTestArray(arr, len(arr))
print("done 2")
l = [i/2 for i in range(40)]
arr = (c_double * len(l))(*l)
lib.CTestArray.argtypes = [type(arr), c_int]
lib.CTestArray(arr, len(arr))
定義一個小函數來完成這項工作可能是最明智的,例如:
import ctypes
lib = ctypes.cdll.LoadLibrary("./main.so")
lib.CTestArray.restype = None
def CTestArray(l):
arr = (ctypes.c_double * len(l))(*l)
lib.CTestArray.argtypes = [type(arr), ctypes.c_int]
lib.CTestArray(arr, len(arr))
CTestArray([1, 3, .5, 2, 1, 1, 2, 3, .5, 3, 1, 1, 3, 1, 1, 3, 2, 1])
CTestArray([42, 3.1415])
CTestArray([i/2 for i in range(40)])
當然,在這一點上,設置參數類型有點傻。
- 1 回答
- 0 關注
- 194 瀏覽
添加回答
舉報