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模块中有能找到.我们来看一下这图:

001.png

这里可以很清楚的看到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

总结

  1. Python与Go之间的参数传递, 处理非INT型时需要都转为对应的C类型
  2. ctypes需要显式地声明DLL函数的参数和返回期望的数据类型
  3. 注意在Python3中字符串bytes和string的区别
  4. Go模块需要//export 声明外部可调用
  5. Go处理C的类型是需要显式转换

用Golang为Python编写模块的更多相关文章

  1. 用C或C++为Python编写模块

    1.使用c或c++编写对应的函数例如: //modtest.c int abs(int number){ ){ return -number; } else{ return number; } } 2 ...

  2. Day5 模块及Python常用模块

    模块概述 定义:模块,用一砣代码实现了某类功能的代码集合. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,提供了代码的重用性.在Python中,一个.py文件就称之为一个模块(Mod ...

  3. Day6 模块及Python常用模块

    模块概述 定义:模块,用一砣代码实现了某类功能的代码集合. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,提供了代码的重用性.在Python中,一个.py文件就称之为一个模块(Mod ...

  4. python基础----模块、包

    一 模块                                                                                                 ...

  5. Python基础-模块与包

    一.如何使用模块 上篇文章已经简单介绍了模块及模块的优点,这里着重整理一下模块的使用细节. 1. import 示例文件:spam.py,文件名spam.py,模块名spam #spam.py pri ...

  6. Python编程-模块和包

    一.模块 1.什么是模块? 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 2.为何要使用模块? 如果你退出python解释器然后重新进入,那么你之前定义的函 ...

  7. 使用 python 编写一个授权登录验证的模块

    使用 python 编写一个授权登录验证的模块 我们编写的思路: 1.登录的逻辑:如果用户名和密码正确,就返回 token . 2.生成 token 的逻辑,根据用户名,随机数,当前时间 + 2 小时 ...

  8. python编写banner获取的常用模块

    模块的概念:模块也叫库,每个模块中都内置了大量的功能和函数.类和变量.它就像是积木,可以根据需要进行调用组合.模块就是程序,每个模块就是一个后缀为.py的Python程序.Python的模块分为标准模 ...

  9. python常用模块(模块和包的解释,time模块,sys模块,random模块,os模块,json和pickle序列化模块)

    1.1模块 什么是模块: 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文 ...

随机推荐

  1. HAWQ取代传统数仓实践(十五)——事实表技术之无事实的事实表

    一.无事实事实表简介 在多维数据仓库建模中,有一种事实表叫做"无事实的事实表".普通事实表中,通常会保存若干维度外键和多个数字型度量,度量是事实表的关键所在.然而在无事实的事实表中 ...

  2. 几个Unity3d UI制作的解决方案.

    1.ex2D的渲染机制 (高效的原因) 在以往的2D插件中,渲染方式是每个sprite单独渲染,由Unity负责Dynamic Batching.在新版ex2D中,我们经过严谨的优化实现了独立的dyn ...

  3. Reinforcement Learning Q-learning 算法学习-3

    //Q-learning 源码分析. import java.util.Random; public class QLearning1 { private static final int Q_SIZ ...

  4. 洛谷P3585 [POI2015]PIE

    传送门 题目大意:有个n*m的格子图,要求'x'点要被染成黑色 有个a*b的印章,'x'是可以染色的印章上的点. 要求用印章去染色格子 (1)印章不可以旋转. (2)不能把墨水印到纸外面. (3)纸上 ...

  5. js中typeof用法详细介绍

    typeof 运算符把类型信息当作字符串返回,包括有大家常有变量类型.   typeof 运算符把类型信息当作字符串返回.typeof 返回值有六种可能: "number," &q ...

  6. Log4j日志配置说明

    一.Log4j简介 Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局).这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出.综合使 ...

  7. stp 零部件 转为 装配图

    stp 零部件 转为 装配图 起因 由于收到的 stp 为零件件,这时如果输出 eDrawings 文件时是没有装配结构的. 解决 打开 stp 后在资源管理器中有一个实体的文件夹,点右键保存实体. ...

  8. 洛谷3778 [APIO2017]商旅

    题目:https://www.luogu.org/problemnew/show/P3778 一看就是0/1分数规划.但不能直接套模板,因为有个商品种类的限制. 考虑从a买在b卖,商品种类根本没用,关 ...

  9. 使用nagios插件 check_mysql_health 过程中遇到的error

    使用nagios插件 check_mysql_health 过程中遇到的error 1.如果在运行监控mysql插件的时候遇到了error安装以下依赖包就可以解决: yum install perl- ...

  10. linux的审计功能(audit)

    为了满足这样的需求:记录文件变化.记录用户对文件的读写,甚至记录系统调用,文件变化通知.什么是auditThe Linux Audit Subsystem is a system to Collect ...