Golang 调用 Python 代码

Golang 调用 Python 代码,第1张

概述go 中的 cgo 模块可以让 go 无缝调用 c 或者 c++ 的代码,而 python 本身就是个 c 库,自然也可以由 cgo 直接调用,前提是指定正确的编译条件,如 Python.h 头文件(),以及要链接的库文件。本文以 Ubuntu 18.04 作为开发和运行平台进行演示。 其实在使用 cgo 之前,笔者也考虑过使用 grpc 的方式。比如可以将需要调用的 python 代码包装成一个

go 中的 cgo 模块可以让 go 无缝调用 c 或者 c++ 的代码,而 python 本身就是个 c 库,自然也可以由 cgo 直接调用,前提是指定正确的编译条件,如 Python.h 头文件(),以及要链接的库文件。本文以 Ubuntu 18.04 作为开发和运行平台进行演示。

其实在使用 cgo 之前,笔者也考虑过使用 grpc 的方式。比如可以将需要调用的 python 代码包装成一个 grpc server 端,然后再使用 go 编写对应的 clIEnt 端,这样考虑的前提是,go 调用 python 代码本来就是解一时之困,而且引入语言互 *** 作后,对于项目维护和开发成本控制都有不小的影响,如果直接使用 grpc 生成编程语言无感知的协议文件,将来无论是重构或使用其他语言替换 python 代码,都是更加方便,也是更加解耦的。所以 grpc 也是一种比较好的选择。至于通信延迟,老实说既然已经设计语言互 *** 作,本机中不到毫秒级的损失其实也是可以接受的。

接下来进入正题。

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 --cflagspython3.6-config --ldflags

以下是对应的输出

-I/usr/include/python3.6m -I/usr/include/python3.6m  -Wno-unused-result -Wsign-compare -g -fdeBUG-prefix-map=/build/python3.6-MtRqCA/python3.6-3.6.6=. -specs=/usr/share/dpkg/no-pIE-compile.specs -fstack-protector -Wformat -Werror=format-security  -DNDEBUG -g -fwrapv -O3 -Wall-L/usr/lib/python3.6/config-3.6m-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 : -I./ -I/usr/include/python3.6m//#cgo LDFLAGS: -L/usr/lib/python3.6/config-3.6m-x86_64-linux-gnu -L/usr/lib -lpython3.6m -lpthread -ldl  -lutil -lm//#include "Python.h"import "C"

3. 部分示例代码

3.0 映射 PyObject

type PyObject struct {    ptr *C.PyObject}func togo(obj *C.PyObject) *PyObject {    if obj == nil {        return nil    }    return &PyObject{ptr: obj}}func topy(self *PyObject) *C.PyObject {    if self == nil {        return nil    }    return self.ptr}

3.1 python 环境的启动与终结

func Initialize() error {    if C.Py_IsInitialized() == 0 {        C.Py_Initialize()    }    if C.Py_IsInitialized() == 0 {        return fmt.Errorf("python: Could not initialize the python interpreter")    }    if C.PyEval_ThreadsInitialized() == 0 {        C.PyEval_InitThreads()    }    if C.PyEval_ThreadsInitialized() == 0 {        return fmt.Errorf("python: Could not initialize the GIL")    }    return nil}func Finalize() error {    C.Py_Finalize()    return nil}

3.2 包路径与模块导入

func InsertExtraPackageModule(dir string) *PyObject {    sysModule := importModule("sys")    path := sysModule.GetAttrString("path")    cstr := C.CString(dir)    defer C.free(unsafe.Pointer(cstr))    C.PyList_Insert(topy(path),C.Py_ssize_t(0),topy(togo(C.PyBytes_FromString(cstr))))    return importModule(dir)}func importModule(name string) *PyObject {    c_name := C.CString(name)    defer C.free(unsafe.Pointer(c_name))    return togo(C.Pyimport_importModule(c_name))}func (self *PyObject) GetAttrString(attr_name string) *PyObject {    c_attr_name := C.CString(attr_name)    defer C.free(unsafe.Pointer(c_attr_name))    return togo(C.PyObject_GetAttrString(self.ptr,c_attr_name))}

3.3 数据类型转换

func PyStringFromGoString(v string) *PyObject {    cstr := C.CString(v)    defer C.free(unsafe.Pointer(cstr))    return togo(C.PyBytes_FromString(cstr))}func PyStringAsGoString(self *PyObject) string {    c_str := C.PyBytes_Asstring(self.ptr)    return C.GoString(c_str)}...

可以看到形似 C.Py* 的方法都是由 cgo 模块编译调用的,这些方法也是 python 暴露的 C-API,而这里的示例就到此为止,其他诸如调用 python 模块方法的功能文档里也描述得十分详细,尽管实施起来仍然有些麻烦。

但是请注意 C-API 的 2.x 与 3.x 版本仍有不同,比如 2.x 版本中的字符串 *** 作类型 PyString_* 在 3.x 中便被重命名为 PyBytes_*

关注过 go 与 python 互 *** 作功能的同学应该注意到上述的示例代码部分来自 go-python 这个开源项目,有兴趣的同学也可以关注一下。 这个项目基于 python2.7 ,其中暴露的 API 诸如字符串转换也是基于 python2.x 版本,所以针对于更流行的 python3.x 项目,大家就需要自己按照上文方法做一些修改了。

实际工作中,语言的互 *** 作场景确实很让人感觉头疼,而 cgo 的文档资料其实并不多,所以希望本文能给大家带来一些帮助。

总结

以上是内存溢出为你收集整理的Golang 调用 Python 代码全部内容,希望文章能够帮你解决Golang 调用 Python 代码所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1269781.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存