一、环境配置
作者使用的设备是m1,目前系统版本是13.3.1 (22E261)
1、golang版本
因为要使用go-python库,所以还只能选择cmd64的golang版本。
2、python版本
用aconda创建一个python3.7即可,go-python3这个库目前还只能用python3.7,十分恼火。
3、go-python
导入这个库即可
github.com/DataDog/go-python3 v0.0.0-20211102160307-40adc605f1fe
二、核心功能
最主要的部分就是go-python库的调用,这里面有很多坑,而且报错都没有具体提示的那种,所以还是多花时间调一下,看看到底哪里在出问题。然后gin框架搭后端服务器这个在前面有所讲述,这里就主要讲讲go-python用到的东西,以及解决的bug。
1、项目结构
这里结构应该还比较易读,go调python的部分我当作一个controller写在这里。
2、具体代码
接下来我从头到尾讲一下代码怎么写以及为什么要这么写。首先go-python3的调用需要先进行初始化,下面这句话就是,我把它放在了init()函数中,因为这个地方作为一个controller,当前端提交一次post请求这个地方就会运行一遍,这过程中就容易报错,所以我就只让它在整个框架运行的时候初始化一次。这个对应的结束语句我在下面注释掉了,原因在旁边也写上了。更深层的原因不得而知。
python3.Py_Initialize()
接下来是这段,importMoudule的目的是将我们写好的iris.py作为一个库导进来,然后result是我们需要调用的函数,python代码会在后面放出来,这里也只让它初始化一次,不然会报错。
iris = importModule("./pkg/web/controller/python", "iris") resultFunc = iris.GetAttrString("result")
然后是获取前端提交的参数,这里不知道是什么问题,之前还可以直接通过postform获取,这里只能创建一个结构体,然后通过绑定的形式接受参数。
var requestValue Iris _ = c.BindJSON(&requestValue)
接下来为了把这个参数能够传给py文件,首先定义了一个PyTuple,应该是个tuple类型,(这里起初我想用List传,但总失败)。就是定义了一个PyTuple的对象,然后通过SetItem方法,把值放进去,然后通过call函数,来调用前面的resultFunc,也就是py文件中的result函数。最后通过返回的对象去获取一个str,也就是我们要的预测的分类结果。
var x = python3.PyTuple_New(1) python3.PyTuple_SetItem(x, 0, python3.PyUnicode_FromString(requestValue.Array)) res = resultFunc.Call(x, python3.Py_None) str = python3.PyUnicode_AsUTF8(res.Repr())
最后再把这个结果返回给前端,整个流程 over!
if len(requestValue.Array) == 4 { c.JSON(0, gin.H{ "data": str, }) } else { c.JSON(0, gin.H{ "data": "预测失败", }) }
package controller
import (
"fmt"
"github.com/DataDog/go-python3"
"github.com/gin-gonic/gin"
)
var iris *python3.PyObject
var resultFunc *python3.PyObject
var str string
var res *python3.PyObject
func init() {
python3.Py_Initialize()
iris = importModule("./pkg/web/controller/python", "iris")
resultFunc = iris.GetAttrString("result")
}
func importModule(dir, name string) *python3.PyObject {
sysModule := python3.PyImport_ImportModule("sys")
path := sysModule.GetAttrString("path")
python3.PyList_Insert(path, 0, python3.PyUnicode_FromString(dir))
return python3.PyImport_ImportModule(name)
}
type Iris struct {
Array string `json:"value"`
}
func IrisController(c *gin.Context) {
var requestValue Iris
_ = c.BindJSON(&requestValue)
var x = python3.PyTuple_New(1)
python3.PyTuple_SetItem(x, 0, python3.PyUnicode_FromString(requestValue.Array))
res = resultFunc.Call(x, python3.Py_None)
str = python3.PyUnicode_AsUTF8(res.Repr())
fmt.Println(str)
//python3.Py_Finalize() 不注释就只能查一次
if len(requestValue.Array) == 4 {
c.JSON(0, gin.H{
"data": str,
})
} else {
c.JSON(0, gin.H{
"data": "预测失败",
})
}
}
3、python代码
这里就是调库使用了一下模型,然后定一个函数来进行值的接收和回传。
from sklearn.datasets import load_iris
import numpy as np
from sklearn.tree import DecisionTreeClassifier
data=load_iris()
train=load_iris().get("data")
target=load_iris().get("target")
clf=DecisionTreeClassifier()
clf.fit(train,target)
tname=data.get("target_names")
def result(list):
input=[]
for i in range(4):
input.append(int(list[i]))
result=tname[clf.predict(np.array([input]))]
result=str(result[0])
return result
三、效果
1、提交json数据
2、返回分类结果
四、总结
博客10分钟写完,写bug写一天