简介: # 简介 ## 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-configprefix=/System/Library/Frameworks/Python.framework/Versions/2.7exec_prefix=${prefix}libdir=${exec_prefix}/libincludedir=${prefix}/includeName: PythonDescription: Python libraryRequires:Version: 2.7Libs.private: -ldl  -framework CoreFoundationLibs: -L${libdir} -lpython2.7Cflags: -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通过,阐明配置胜利了。

5、独自执行test。须要增加下PYTHONPATH环境变量,否则将导入不了python包。

export PYTHONPATH=.:$PYTHONPATHcd go-python/tests/kw-argsgo run main.goimporting kwargs...args=() kwds={}args=() kwds={'a': 3}

样例

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

package mainimport (    "fmt"    "github.com/sbinet/go-python")// 初始化go-pythonfunc 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,通过缩小援用计数的形式开释对象,否则会产生内存透露。

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