最近有一个项目需要在服务端调用Python3.7写的算法,网上找了一圈,发现两个库都使用cgo特性调用了Python的C-API:
针对Python2:https://github.com/sbinet/go-pythongithub.com
针对Python3:https://github.com/DataDog/go-python3github.com
由于我这边的算法是Python3.7写的,自然使用go-python3这个库,安装方法也简单,使用下面的命令:
go get github.com/DataDog/go-python3
安装库时,可能会提示找不到python3.pc这个文件,这时可以先安装对应有dev包,用pyenv就可以安装,然后配置PKG_CONFIGPATH到对应的pkgconfig文件下,那里会有python3.pc。重新配置好PKG_CONFIG_PATH后,再执行go get命令应该就不会报错了。
参考命令如下:
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/Users/yourname/.pyenv/versions/3.7-dev/lib/pkgconfig/
Golang中调用Python3时,一定要注意设置包的查找路径,参考代码如下:
func ImportModule(dir, name string) *python3.PyObject {
sysModule := python3.PyImport_ImportModule("sys")
path := sysModule.GetAttrString("path")
python3.PyList_Insert(path, 0, python3.PyUnicode_FromString("/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages"))
python3.PyList_Insert(path, 0, python3.PyUnicode_FromString(dir)
return python3.PyImport_ImportModule(name)
}
上面函数直接对系统的PATH变量进行了配置,dir变量用来传入自定义的模块路径(自已写的算法包等等),name是算法包的名字。
正常的调用步骤为:python3.Py_Initialize()初始化调用环境;
引入模块;
GetAttrString()得到算法包;
配置传入参数,调用Call()执行算法;
解析算法返回的结果;
python3.Py_Finalize()销毁Python3运行环境。
这里给出示例代码如下:
func PyTest() {
python3.Py_Initialize()
if !python3.Py_IsInitialized() {
fmt.Println("Error initializing the python interpreter")
os.Exit(1)
}
v := ImportModule("/Users/yourname/Desktop/lab/pppython", "value_pp")
b := v.GetAttrString("estimate_pp")
fmt.Printf("[FUNC] b = %#v\n", b)
bArgs := python3.PyTuple_New(1)
python3.PyTuple_SetItem(bArgs, 0, python3.PyUnicode_FromString("/Users/yourname/Desktop/lab/pppython/srcdata/67.csv"))
re := b.Call(bArgs, python3.Py_None)
fmt.Println("IsCallable: ", python3.PyCallable_Check(b))
re1 := python3.PyTuple_GetItem(re, 0)
re2 := python3.PyTuple_GetItem(re, 1)
fmt.Println("re1:", python3.PyLong_AsLong(re1))
fmt.Println("re2:", python3.PyLong_AsLong(re2))
python3.Py_Finalize()
}
由于算法中返回多个值时对应的是Tuple,所以上面采用了PyTupleGetItem来得到相应的元素,但拿到这个值还不能直接输出使用,因为它还是PyObject类型,需要根据实际类型再调用As相关的函数进行一次转化后再输出,比如这里用的是pythone.PyLong_AsLong。
go-python3这个库的源码比较简单,可以直接查看,也可以对比https://docs.python.org/3.7/c-api/index.html去理解。这里写的是Python3的调用方法,至python2相关的可以参考GO语言中文网的一篇文章https://studygolang.com/articles/11155studygolang.com
里面用的是go-python库。