简介: # 简介 ## go-python Python提供了丰富的[C-API](https://docs.python.org/2/c-a...。而C和Go又可以通过cgo无缝集成。所以,直接通过Golang调用libpython,就可以实现Go调Python的功能了。但是过程比较复杂,而[go-python](https://github.com/sbinet/go-...

简介

go-python

Python提供了丰富的C-API。而C和Go又可以通过cgo无缝集成。所以,直接通过Golang调用libpython,就可以实现Go调Python的功能了。但是过程比较复杂,而go-python提供了针对CPython-2的C-API提供了native-binding能力,方便实现了Go到Python的调用。

但是目前,go-python只支持python2.7。

pkg-config

go-python使用pkg-config来获取python的头文件及库信息。

​ 一般来说,如果库的头文件不在/usr/include目录中,那么在编译的时候需要用-I参数指定其路径。由于同一个库在不同系统上可能位于不同的目录下,用户安装库的时候也可以将库安装在不同的目录下,所以即使使用同一个库,由于库的路径的不同,造成了用-I参数指定的头文件的路径和在连接时使用-L参数指定lib库的路径都可能不同,其结果就是造成了编译命令界面的不统一。pkg-config就是用来解决编译连接界面不统一问题的一个工具。

pkg-config的基本思想是通过库提供的一个.pc文件获得库的各种必要信息的,包括版本信息、编译和连接需要的参数等。这样,不管库文件安装在哪,通过库对应的.pc文件就可以准确定位,可以使用相同的编译和连接命令,使得编译和连接界面统一。

环境配置(MAC为例)

1、本地找到python-2.7.pc文件。如果没有则创建一个。特别注意,prefix要指定为python2.7的library路径。# See: man pkg-config

prefix=/System/Library/Frameworks/Python.framework/Versions/2.7

exec_prefix=${prefix}

libdir=${exec_prefix}/lib

includedir=${prefix}/include

Name: Python

Description: Python library

Requires:

Version: 2.7

Libs.private: -ldl -framework CoreFoundation

Libs: -L${libdir} -lpython2.7

Cflags: -I${includedir}/python2.7

2、将python-2.7.pc路径添加到环境变量$PKG_CONFIG_PATH中

3、验证结果:pkg-config --cflags -- python-2.7

-I/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7

4、执行make VERBOSE=1,第一次执行可能会提示go-python命令找不到。将gopath的bin路径添加到环境变量$PATH即可。如下图ut通过,说明配置成功了。

9bbf3654f6c863c220323c29a502723a.png

5、单独执行test。需要添加下PYTHONPATH环境变量,否则将导入不了python包。export PYTHONPATH=.:$PYTHONPATH

cd go-python/tests/kw-args

go run main.go

importing kwargs...

args=() kwds={}

args=() kwds={'a': 3}

样例

使用python的cPickle模块,通过 dumps将python对象序列化保存到一个字符串变量中,通过loads从字符串变量中载入python对象。package main

import (

"fmt"

"github.com/sbinet/go-python"

)

// 初始化go-python

func init() {

err := python.Initialize()

if err != nil {

panic(err.Error())

}

}

func main() {

gostr := "foo" //定义goloang字符串

pystr := python.PyString_FromString(gostr) //将golang字符串专程python字符串

str := python.PyString_AsString(pystr) //将python字符串,再转为golang字符串。

fmt.Println("hello [", str, "]")

pickle := python.PyImport_ImportModule("cPickle") //导入cPickle模块

if pickle == nil {

panic("could not import 'cPickle'")

}

dumps := pickle.GetAttrString("dumps") //获取dumps函数

if dumps == nil {

panic("could not retrieve 'cPickle.dumps'")

}

defer dumps.DecRef() //减少引用计数,释放资源。

out := dumps.CallFunctionObjArgs("O", pystr) //针对python字符串进行dumps操作。

if out == nil {

panic("could not dump pystr")

}

defer out.DecRef()

fmt.Printf("cPickle.dumps(%s) = %q\n", gostr,

python.PyString_AsString(out),

)

loads := pickle.GetAttrString("loads") //获取loads函数

if loads == nil {

panic("could not retrieve 'cPickle.loads'")

}

defer loads.DecRef()

out2 := loads.CallFunctionObjArgs("O", out) //将dumps结果重新loads

if out2 == nil {

panic("could not load back out")

}

defer out2.DecRef()

fmt.Printf("cPickle.loads(%q) = %q\n",

python.PyString_AsString(out),

python.PyString_AsString(out2),

)

}

机制简介

整个go-python的核心在于处理PyObject跟golang类型的关系。在Python内部,PyObject结构体用来保存全部对象共同的数据成员,以及实现GC机制所须要的一些辅助字段等,所以说PyObjectPython对象机制的基础。sequence.go: 处理了PyObject跟golang内置类型的转换。典型的例如:PyString_FromString是将golang string转换为python string,即PyObject;PyString_AsString是将PyObject转换为golang string。

object.go:关于PyObject的一些核心操作。例如:获取函数对象GetAttr,及响应函数对象的调用CallFunctionObjArgs等。其本质是对python C扩展的封装。如下所示:func (self *PyObject) GetAttr(attr_name *PyObject) *PyObject {

return togo(C.PyObject_GetAttr(self.ptr, attr_name.ptr))

}

注意事项:

所有的PyObject对象使用结束,需要主动调用DecRef,通过减少引用计数的方式释放对象,否则会产生内存泄漏。

原文链接

本文为阿里云原创内容,未经允许不得转载。