如何使用ctypes将数组从Go [lang]返回到Python?

时间:2018-08-14 15:37:05

标签: python numpy go ctypes ffi

我正在尝试编写一些代码,这些代码在GoLang中创建一个数组,并将其返回给python脚本ctypes(和一些numpy)。到目前为止,我无法获得任何帮助,我也无法弄清楚为什么……我将不胜感激!

我的Go代码如下所示:

func Function(physics_stuff... float64,  N int ) []float64{
    result := make([]float64, N)
    for i:= 0; i< N; i++{
        result[i] =  blah....
    }
    return result;
}

并且我目前正在尝试使用以下功能将该功能导入python:

from ctypes import c_double, cdll, c_int
from numpy.ctypeslib import ndpointer

lib = cdll.LoadLibrary("./go/library.so")
lib.Function.argtypes = [c_double]*6 + [c_int]

def lovely_python_function(stuff..., N):
    lib.Function.restype = ndpointer(dtype = c_double, shape = (N,))
    return lib.Function(stuff..., N)

此python函数永不返回。来自同一库的其他函数也可以正常工作,但是它们都返回一个float64(在python中为c_double)。

1 个答案:

答案 0 :(得分:4)

在您的代码restype中期望使用_ndtpr类型,请参见:

lib.Function.restype = ndpointer(dtype = c_double, shape = (N,))

也可以在numpy文档中查看:

  

def ndpointer(dtype = None,ndim = None,shape = None,flags = None)

     

[其他文本]

     

返回

     

klass:ndpointer类型的对象

     
    

类型对象,它是一个包含{br />的_ndtpr实例     dtype,ndim,形状和标志信息。

  
     

[其他文本]

通过这种方式lib.Function.restype是指针类型,而Golang中的适当类型必须是unsafe.Pointer

但是,您需要一个需要作为指针传递的切片:

func Function(s0, s1, s2 float64, N int) unsafe.Pointer {
    result := make([]float64, N)
    for i := 0; i < N; i++ {
        result[i] = (s0 + s1 + s2)
    }
    return unsafe.Pointer(&result)//<-- pointer of result
}

这会导致在Go和C之间传递指针的规则中出现问题。

  
      
  1. 调用返回后,C代码可能不会保留Go指针的副本。
  2.   
     

来源:https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md

因此,您必须将unsafe.Pointer转换为uintptr golang类型。

func Function(s0, s1, s2 float64, N int) uintptr {
    result := make([]float64, N)
    for i := 0; i < N; i++ {
        result[i] = (s0 + s1 + s2)
    }
    return uintptr(unsafe.Pointer(&result[0]))//<-- note: result[0]
}

这样,您就可以正常工作!

注意:C中的切片结构由typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;表示,但是C仅期望数据,因为这仅是需要结果void *data(第一个字段或字段[0])。

PoC:https://github.com/ag-studies/stackoverflow-pointers-ref-in-golang