用Golang为Python编写模块
Go里面需要显示的引入C模块, 让编译器支持生成动态链接库, 并且在代码中可以使用C语言的数据类型,这个至关重要. Calling Go code from Python code 摘取一个最简单例子
//libadd.go
package main
import "C"
//export add
func add(left, right int) int {
return left + right
}
func main() {
}
go build -buildmode=c-shared -o libadd.so libadd.go
from ctypes import cdll
lib = cdll.LoadLibrary('./libadd.so')
print("Loaded go generated SO library")
result = lib.add(2, 3)
print(result)
The cgo export command is documented in
go doc cgo, section "C references to Go". Essentially, write//export FUNCNAMEbefore the function definition
有这么一段话, 需要显式注释//export add 把 add函数公开给C调用
本以为很简单的就能用, 兴致满满地把例子改一下, 改为简单的处理字符串的时候, 却发现跑不起来了.
//libadd.go
package main
import "C"
//export add
func add(left, right string) string {
return left + right
}
func main() {
}
from ctypes import CDLL
lib = CDLL('./libadd.so')
print("Loaded go generated SO library")
result = lib.add("Hello", "World")
print(result)
这时候运行是出错的
再次翻看资料发现这么一句话:
The python code is really short and this is only passing an integer back and forth (more complex string and struct cases are much more challenging).
这说明处理字符串的时候并不是简单改成string类型就可以.这时候翻开了BUILDING PYTHON MODULES WITH GO 1.5 , 这时能找到的最全面的资料, 可惜里面的过程都过于复杂, 整个思路是用Go去写C code, 类似写解释器一样, 去抽象出PyObject然后按照API标准来注册、处理、返回.我仅是希望以动态链接库 的方式来能调用就可以了.
我开始思考, 为何例子中使用int类型就可以, 我改成一个简单的接收string 返回string 却一直失败. py是利用ctypes来跟so模块进行交互, 这里存在一个代码的翻译过程 Py -> C -> Go, 我能想到的对于字符串数据类型的处理不一样原因引起(后面事实证明了我的猜想).那么思考一下, Py中的字符串传递到Go里面去使用什么类型来接收呢? 翻阅了大量资料, 所有答案在Python Doc 官网关于ctypes模块中有能找到.我们来看一下这图:
这里可以很清楚的看到Python3 ctypes中字符串 bytes 和 string 是对应的两种指针类型.同时提供了argtypes 和 restype 来显式转换动态链接库中函数的参数和返回类型.(参考StackOverFlow)
这时候按照思考的流程来修改代码
//libadd.go
package main
import "C"
//export add
func add(left, right *C.char) *C.char {
// bytes对应ctypes的c_char_p类型,翻译成C类型就是 char *指针
merge := C.GoString(left) + C.GoString(right)
return C.CString(merge)
}
func main() {}
重新编译
go build -buildmode=c-shared -o libadd.so libadd.go
Python中引用
import ctypes
add = ctypes.CDLL('./libadd.so').add
# 显式声明参数和返回的期望类型
add.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
add.restype = ctypes.c_char_p
left = b"Hello"
right = b"World"
print(add(left, right))
正确输出结果:
b"HelloWorld"
就这样, 一个基本的模块就完成, 只要关注传入参数和返回结果的数据类型处理, 我只需要丰富函数的处理逻辑,Go模块中函数内部实现对于Python是透明,只要参数正确即可.其中关于 cgo更多的信息, 大家可以自行查阅Golang.org
总结
- Python与Go之间的参数传递, 处理非INT型时需要都转为对应的C类型
- ctypes需要显式地声明DLL函数的参数和返回期望的数据类型
- 注意在Python3中字符串bytes和string的区别
- Go模块需要
//export声明外部可调用 - Go处理C的类型是需要显式转换
用Golang为Python编写模块的更多相关文章
- 用C或C++为Python编写模块
1.使用c或c++编写对应的函数例如: //modtest.c int abs(int number){ ){ return -number; } else{ return number; } } 2 ...
- Day5 模块及Python常用模块
模块概述 定义:模块,用一砣代码实现了某类功能的代码集合. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,提供了代码的重用性.在Python中,一个.py文件就称之为一个模块(Mod ...
- Day6 模块及Python常用模块
模块概述 定义:模块,用一砣代码实现了某类功能的代码集合. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,提供了代码的重用性.在Python中,一个.py文件就称之为一个模块(Mod ...
- python基础----模块、包
一 模块 ...
- Python基础-模块与包
一.如何使用模块 上篇文章已经简单介绍了模块及模块的优点,这里着重整理一下模块的使用细节. 1. import 示例文件:spam.py,文件名spam.py,模块名spam #spam.py pri ...
- Python编程-模块和包
一.模块 1.什么是模块? 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 2.为何要使用模块? 如果你退出python解释器然后重新进入,那么你之前定义的函 ...
- 使用 python 编写一个授权登录验证的模块
使用 python 编写一个授权登录验证的模块 我们编写的思路: 1.登录的逻辑:如果用户名和密码正确,就返回 token . 2.生成 token 的逻辑,根据用户名,随机数,当前时间 + 2 小时 ...
- python编写banner获取的常用模块
模块的概念:模块也叫库,每个模块中都内置了大量的功能和函数.类和变量.它就像是积木,可以根据需要进行调用组合.模块就是程序,每个模块就是一个后缀为.py的Python程序.Python的模块分为标准模 ...
- python常用模块(模块和包的解释,time模块,sys模块,random模块,os模块,json和pickle序列化模块)
1.1模块 什么是模块: 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文 ...
随机推荐
- SQL中合并两个表的JOIN语句
SQL里有四种JOIN语句用于根据某条件合并两个表: (INNER) JOIN: 交集 LEFT (OUTER) JOIN: 左表数据全包括,右表对应的如果没有就是NULL RIGHT (OUTER) ...
- opencv 识别答题卡
参考这个网站,然后自己 找了张图片试了一下 http://blog.csdn.net/cp562090732/article/details/47804003 // test.cpp : 定义控制台应 ...
- I-O流概念认知升级
在文件操作基础入门中,我们提到了流的 概念,这篇我们将更多的介绍流这个东西,以及C的I/O相关知识 现在,我们从C程序员最熟悉的printf函数开始学习I/O流. 我们对printf函数一直是很喜爱的 ...
- git clone all branch and create a empty branch
/******************************************************************** * git clone all branch and cre ...
- Linux 下安装composer
1.下载composer.phar文件. 2.将composer.phar文件上传linux. 3.执行 php composer.phar 4.全局安装:mv composer.phar /usr/ ...
- Proposition
提供 \(k\) 个变量 \((k\leq 4)\) 可独立取值为 \(0,1\),两种运算分别等价于 \(\neg a\) 和 \(\neg a \lor b\) . 你需要恰好使用 \(n\) 个 ...
- Python之os.path
os.path模块主要用于常用路径名操作,在编程中使用频率特高 os.path常用函数 abspath(path) 返回路径名path的规范化的绝对路径 split(path) 将path分割成目录和 ...
- SSH框架(1)
一. SSH框架相关的面试题: 1. BeanFactory的作用是什么? [中] BeanFactory是配置.创建.管理bean的容器,有时候也称为bean上下文.Bean与bean的依 ...
- postman安装Postman Interceptor 插件
做后端开发避免不了进行接口调试,但是一般的项目都是前后端分离的,如果把前端代码下到本地,较为费事,这个时候就需要一个可以进行接口调试的工具.Postman就是一个不错的选择. Postman是什么? ...
- 剑指offer-第五章优化时间和空间效率(在字符串中第一次出现切只出现一次的字符)
题目:在字符串中第一次出现切只出现一次的字符 思路:用HashMap来存放对应的char值和该char出现的次数.做一次变量就可以得到第一个只出现一次的字符. Java代码: import java. ...