代码之家  ›  专栏  ›  技术社区  ›  Yotam Vaknin

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

  •  4
  • Yotam Vaknin  · 技术社区  · 6 年前

    我试图编写一些代码,在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 回复  |  直到 6 年前
        1
  •  4
  •   Jason Aller    6 年前

    在你的代码里 restype 应为 _ndtpr 类型,请参见:

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

    在numpy文档中也可以看到:

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

    [其他文本]

    退换商品

    klass:ndpointer类型对象

    类型对象,它是 NNTPR 包含的实例
    数据类型、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指针的副本。

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

    所以你必须转换 不安全。指针 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