主要看在go中怎么操作
对引用的python代码初始化
import(
"github.com/DataDog/go-python3"
)
var(
pyTorchModule *python3.PyObject //加载python文件
pyInitFunc *python3.PyObject //python中函数的引用
)
func initModel() {
python3.Py_Initialize() //初始化
if !python3.Py_IsInitialized() {
fmt.Println("Error initializing the python interpreter")
os.Exit(1)
}
path, _ := os.Getwd() //获取当前路径
pyTorchModule = ImportModule(path+"/路径", "python文件名") //引入路径下的xxx.py,函数体在下面
if pyTorchModule == nil {
log.Fatalf("pyTorchModule is nil")
os.Exit(1)
}
pyInitFunc = pyTorchModule.GetAttrString("python中的函数名") //返回python中函数的一个对象。或者说是一个变量,其是python中函数的引用
pyInitFunc.CallFunctionObjArgs() //相当于call(),通过上面的变量调用python中的该函数。
}
func ImportModule(dir, name string) *python3.PyObject { //引入python文件
sysModule := python3.PyImport_ImportModule("sys") //sys model,从sys模块返回对象名称。可以看作初始化语句
path := sysModule.GetAttrString("path") //这个函数可以在文档里查到
python3.PyList_Insert(path, 0, python3.PyUnicode_FromString("")) //这几个也可以从python3官方文档里面找到
python3.PyList_Insert(path, 0, python3.PyUnicode_FromString(dir))
return python3.PyImport_ImportModule(name)
}
然后我们就可以通过调用函数来获取返回的数据了。
go中通过 变量名.CallFunctionObjArgs() 的方法调用python3中的函数,获取python中函数的返回值
将从python中获取的数据转换为go中的浮点数组
先写一个函数,能把数据从类型*python3.Object转换为string
func pythonRepr(o *python3.PyObject) (string, error) { //python3.PyObject转string
if o == nil {
return "", fmt.Errorf("object is nil")
}
s := o.Repr() //函数可以查到
if s == nil {
python3.PyErr_Clear()
return "", fmt.Errorf("failed to call Repr object method")
}
defer s.DecRef()
return python3.PyUnicode_AsUTF8(s), nil //utf-8转Unicode
}
再写一个函数,把go中的string转成float数组
需要注意的是如果python中数组过长会出现数组中中间部分数据被逗号代替的情况
这点需要在python用如下代码解决
numpy.set_printoptions(threshold=数组长度)
继续我们的函数
func strToFloatArry(strArry string) ([]float64, error) { //str转float数组
var strlist, strlft, strright []string
strlft = strings.Split(strArry, "[") //去掉数组中的[ //切片
strright = strings.Split(strlft[1], "]") //去掉]
strlist = strings.Split(strright[0], ",") //去掉,
//log.Println(strlist)
var floatArry []float64
var fo float64
for i := 0; i < len(strlist); i++ {
var s []string
s = strings.Split(strlist[i], " ") //数组中逗号后面有空格,需要先去除
for j := 0; j < len(s); j++ {
if len(s[j]) > 2 { //去掉回车
fo, _ = strconv.ParseFloat(s[j], 64) //这个百度就行
}
}
floatArry = append(floatArry, fo)
}
return floatArry, nil
}
接着我们看看如何向python中传递参数并接受python中函数的返回值,最后将其变为go中的类型
func getGrad(globalW []float64) ([]float64, error) { //根据全局模型计算梯度
runtime.LockOSThread()
_gstate := python3.PyGILState_Ensure() //lock()
//下面的操作是如何向python中函数中传递参数
argArray := python3.PyList_New(len(globalW)) //将数组元素转为*python3.Object类型添加到列表中
for i := 0; i < len(globalW); i++ {
python3.PyList_SetItem(argArray, i, python3.PyFloat_FromDouble(globalW[i]))
}
var result *python3.PyObject
result = pyPrivFunc.CallFunctionObjArgs(argArray) //调用函数,返回*python3.Object类型的梯度数组
//获得返回值后转化为go中的类型
if result == nil {
log.Fatalf("pyPrivFunc is nil")
}
strArry, _ := pythonRepr(result) //先转换为str
if strArry == "" {
log.Fatalf("strArry is nil")
}
var floatArrys []float64
floatArrys, _ = strToFloatArry(strArry) //在str->float[]
python3.PyGILState_Release(_gstate) //释放锁
return floatArrys, nil
}
在go中调用python中的函数时,我们要先把要传入的数据从go中的类型变为python的类型。思路就是建一个python中的列表(list有序)(通过python3.PyList_New() 建立),然后把要传递的参数放到列表中。
最后把这个列表变量输入到CallFunctionObjArgs()中
当python接受到go传递进来的参数的时候是一个list。
你可以通过numpy.array()变成numpy数组用于机器学习