这篇文章给大家分享的是有关Golang调用Python代码的实现方法的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
<强>前言
Python是时髦的机器学习御用开发语言,Golang是大红大紫的新时代后端开发语言.Python很适合让搞算法的写写模型,而Golang很适合提供API服务,两位同志都红的发紫,这里就介绍一下正确搅基的办法。
中去的cgo模块可以让去无缝调用c或c++者的代码,而Python本身就是个c库,自然也可以由cgo直接调用,前提是指定正确的编译条件,如Python。h头文件(),以及要链接的库文件。本文以Ubuntu 18.04作为开发和运行平台进行演示。
其实在使用cgo之前,笔者也考虑过使用grpc的方式,比如可以将需要调用python的代码包装成一个grpc服务器端,然后再使用去编写对应的客户端,这样考虑的前提是,去调用python代码本来就是解一时之困,而且引入语言互操作后,对于项目维护和开发成本控制都有不小的影响,如果直接使用grpc生成编程语言无感知的协议文件,将来无论是重构或使用其他语言替换python代码,都是更加方便,也是更加解耦的,所以grpc也是一种比较好的选择。至于通信延迟,老实说既然已经设计语言互操作,本机中不到毫秒级的损失其实也是可以接受的。
接下来进入正题。
<强> Golang调用python代码
<强> 1。针对python版本安装python-dev
sudo apt install python3.6-dev系统未默认安装python3。x的开发环境,所以假如要通过cgo调用python,需要安装对应版本的开发包。
<强> 2。指定对应的cgo CFLAGS和LDFLAGS选项
对于未由c包装的python代码,python-dev包中内置了python-config工具用于查看编译选项。
python3.6-config ——CFLAGS python3.6-config ——ldflags以下是对应的输出
- i/usr/include/python3.6m - i/usr/include/python3.6m -Wno-unused-result -Wsign-compare - g -fdebug-prefix-map=/构建/python3.6-MtRqCA/python3.6-3.6.6=9娓?/usr/share/dpkg/no-pie-compile。规格-fstack-protector -Wformat -Werror=format-security -DNDEBUG - g -fwrapv o3 - wall
- l/usr/lib/python3.6/config - 3.6 m - x86_64 - linux - gnu - l/usr/lib -lpython3.6m -lpthread -ldl -lutil -lm -xlinker -export-dynamic - wl, o1群- wl, -Bsymbolic-functions
低版本的python也可以在安装开发包后,使用对应的python-config命令打印依赖配置。由于cgo默认使用的编译器不是gcc,所以输出中的部分选项并不受支持,所以最后cgo代码的配置为
//# cgo CFLAGS:我。/我/usr/include/python3.6m
//# cgo LDFLAGS: - l/usr/lib/python3.6/config - 3.6 m - x86_64 - linux - gnu - l/usr/lib -lpython3.6m -lpthread -ldl -lutil - lm
//# include“Python.h"
进口“C"
<强> 3。部分示例代码
3.0映射PyObject
type PyObject struct { ptr * C.PyObject } func 多哥(obj * C.PyObject), * PyObject { ,if obj ==, nil { return 才能;零 ,} ,return , PyObject {ptr: obj} } func topy (self * PyObject), * C.PyObject { ,if self ==, nil { return 才能;零 ,} return self.ptr python}3.1环境的启动与终结
func 初始化(),error { ,if C.Py_IsInitialized (),==, 0, { C.Py_Initialize才能() ,} ,if C.Py_IsInitialized (),==, 0, { return 才能;fmt.Errorf (“python: could not initialize 从而python interpreter") ,} ,if C.PyEval_ThreadsInitialized (),==, 0, { C.PyEval_InitThreads才能() ,} ,if C.PyEval_ThreadsInitialized (),==, 0, { return 才能;fmt.Errorf (“python: could not initialize 从而GIL") ,} return nil } func Finalize (), error { ,C.Py_Finalize () return nil }3.2包路径与模块导入
func InsertExtraPackageModule (dir 字符串),* PyObject { ,sysModule :=, ImportModule (“sys") ,path :=, sysModule.GetAttrString (“path") ,cstr :=, C.CString (dir) ,defer C.free (unsafe.Pointer(装运箱)) ,C.PyList_Insert (topy(路径),C.Py_ssize_t (0), topy(多哥(C.PyBytes_FromString(装运箱)))) ,return ImportModule (dir) } func ImportModule (name 字符串),* PyObject { ,c_name :=, C.CString(名字) ,defer C.free (unsafe.Pointer (c_name)) ,return 多哥(C.PyImport_ImportModule (c_name)) } func (self * PyObject), GetAttrString (attr_name 字符串),* PyObject { ,c_attr_name :=, C.CString (attr_name) ,defer C.free (unsafe.Pointer (c_attr_name)) ,return 多哥(C.PyObject_GetAttrString (self.ptr, c_attr_name)) }