热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Golang如何调用Python代码详解

这篇文章主要给大家介绍了关于Golang如何调用Python代码的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

Python是时髦的机器学习御用开发语言,Golang是大红大紫的新时代后端开发语言。Python很适合让搞算法的写写模型,而Golang很适合提供API服务,两位同志都红的发紫,这里就介绍一下正确搅基的办法。

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 也是一种比较好的选择。至于通信延迟,老实说既然已经设计语言互操作,本机中不到毫秒级的损失其实也是可以接受的。

接下来进入正题。

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=/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 的文档资料其实并不多,所以希望本文能给大家带来一些帮助。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。


推荐阅读
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • Python实现变声器功能(萝莉音御姐音)的方法及步骤
    本文介绍了使用Python实现变声器功能(萝莉音御姐音)的方法及步骤。首先登录百度AL开发平台,选择语音合成,创建应用并填写应用信息,获取Appid、API Key和Secret Key。然后安装pythonsdk,可以通过pip install baidu-aip或python setup.py install进行安装。最后,书写代码实现变声器功能,使用AipSpeech库进行语音合成,可以设置音量等参数。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 网络请求模块选择——axios框架的基本使用和封装
    本文介绍了选择网络请求模块axios的原因,以及axios框架的基本使用和封装方法。包括发送并发请求的演示,全局配置的设置,创建axios实例的方法,拦截器的使用,以及如何封装和请求响应劫持等内容。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • centos安装Mysql的方法及步骤详解
    本文介绍了centos安装Mysql的两种方式:rpm方式和绿色方式安装,详细介绍了安装所需的软件包以及安装过程中的注意事项,包括检查是否安装成功的方法。通过本文,读者可以了解到在centos系统上如何正确安装Mysql。 ... [详细]
  • Gitlab接入公司内部单点登录的安装和配置教程
    本文介绍了如何将公司内部的Gitlab系统接入单点登录服务,并提供了安装和配置的详细教程。通过使用oauth2协议,将原有的各子系统的独立登录统一迁移至单点登录。文章包括Gitlab的安装环境、版本号、编辑配置文件的步骤,并解决了在迁移过程中可能遇到的问题。 ... [详细]
  • 本文介绍了在sqoop1.4.*版本中,如何实现自定义分隔符的方法及步骤。通过修改sqoop生成的java文件,并重新编译,可以满足实际开发中对分隔符的需求。具体步骤包括修改java文件中的一行代码,重新编译所需的hadoop包等。详细步骤和编译方法在本文中都有详细说明。 ... [详细]
  • 微软评估和规划(MAP)的工具包介绍及应用实验手册
    本文介绍了微软评估和规划(MAP)的工具包,该工具包是一个无代理工具,旨在简化和精简通过网络范围内的自动发现和评估IT基础设施在多个方案规划进程。工具包支持库存和使用用于SQL Server和Windows Server迁移评估,以及评估服务器的信息最广泛使用微软的技术。此外,工具包还提供了服务器虚拟化方案,以帮助识别未被充分利用的资源和硬件需要成功巩固服务器使用微软的Hyper - V技术规格。 ... [详细]
  • 前言:原本纠结于Web模板,选了Handlebars。后来发现页面都是弱逻辑的,不支持复杂逻辑表达式。几乎要放弃之际,想起了Javascript中ev ... [详细]
  • pytorch Dropout过拟合的操作
    这篇文章主要介绍了pytorchDropout过拟合的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完 ... [详细]
author-avatar
风过无痕啦啦
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有