Golang调用Python代码的实现方法

  介绍

这篇文章给大家分享的是有关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))   }

Golang调用Python代码的实现方法