用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 FUNCNAME
before 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模块 什么是模块: 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文 ...
随机推荐
- ng 自定义服务
服务的本质是对象. 创建服务的常见方式:factory(返回对象) service (方法.属性)constant(常量服务) value(变量服务) 1.factoryapp.factory('服务 ...
- Go开发Struct转换成map两种方式比较
最近做Go开发的时候接触到了一个新的orm第三方框架gorose,在使用的过程中,发现没有类似beego进行直接对struct结构进行操作的方法,有部分API是通过map进行数据库相关操作,那么就需要 ...
- (九)java位运算符
位运算符 &(与),|(或),^(异或),~(取反),<<(左移),>>(右移),>>>(无符号右移) 1:为true,0为false ...
- Dreamweaver_CS6安装与破解
Adobe Dreamweaver是一款非常好用的web前端设计工具,这里详细讲解CS6版本的安装及破解步骤.经过测试,CS5版本也可以使用本经验中共享的破解补丁进行破解. 工具/原料 Dreamwe ...
- C#编程的几个建议
1.属性(properties) 抽象属性可以放在接口的定义里.如: public interface INameValuePair<T> { string Nam ...
- 双色球基础分析--SQL
代码是心血来潮编写得,就象买彩票一样,为国家做贡献:首先建立一个表,表得数据可以从福利彩票网站上获得,自己一个一个得录入进去先: 表结构为: ) NOT NULL , --期数 [F1] [i ...
- 解决 Flask-sqlalchemy 中文乱码
当在使用 flask-sqlalchemy 操作 mysql 数据库时中文乱码或者直接报错. 解决方法如下: from flask_sqlalchemy import SQLAlchemy db = ...
- java向数据库插入时间
tbUrsMember.setMemberRegisterTime(new Date(System.currentTimeMillis()));
- log框架集成
使用slf4j,slf4j相当于一个接口,我们面对接口编程,方便地集成其他的日志框架,我们按照slf4j的标准,日志就会相应地打入日志系统中(log4j 使用slf4j要有两个包1,他本身的api,2 ...
- oracle驱动包maven下载失败解决
oracle是付费的,因此jar包也不是随便让人下的,这就给maven的下载和编译带来了麻烦,因为我们没法从maven仓库直接拿来用.解决办法就是先从别的地方获取jar包,再放到本地仓库里去,这样运行 ...