前言
Python 可以通过 ctypes 模块调用 C 语言实现的函数,调用的方式很简单:
- 创建一个 c 文件,然后编写对应的函数
- 使用 c 编译器创建一个动态链接库文件(.so)
- 在 Python 文件中创建一个
CDLL
的实例
- 最后通过
{CDLL_instance}.{function_name}({function_parameters})
格式调用 c 语言对应的函数
步骤一
// my_functions.c.
#include <stdio.h>
int square(int i) {
return i * i;
}
步骤二
使用下述命令,创建 so 文件
cc -fPIC -shared -o my_functions.so my_functions.c
步骤三&四
调用 C 的函数
>>> from ctypes import *
>>> so_file = "/Users/leetao/workspace/python/test/my_functions.so"
>>> my_functions = CDLL(so_file)
>>>
>>> print(type(my_functions))
<class 'ctypes.CDLL'>
>>>
>>> print(my_functions.square(10))
100
>>> print(my_functions.square(8))
64
>>>
调用 GO 代码
从上面的 C 语言的调用过程,不难发现,最重要的是生成的 .so
文件,如果我们可以将 go 编辑成 .so
文件就可以得到 Python 调用 Go 的目的了。
CGO
Go 有个标准库 CGO 可以用来创建调用 C 代码的 Go 包,当然反过来也可以。
例子
package main
import "C" //必须引入C库
import "fmt"
//加入下面注释代码,表示导出,可以被python调用
//export Sum
func Sum(a int, b int) int {
return a + b
}
func main() {
//必须加一个main函数,作为CGO编译的入口,无具体实现代码
}
需要注意的是:
- 注释 //export Sum 在编译 动态库(dll ,so)的时候是必须的,说明了动态库需要输出的函数
- main函数必须写,没有执行代码,作为CGO编译的入口
- 必须引入C库(import "C")
编译动态库
使用下面的命令进行编译
go build -buildmode=c-shared -o s1.so s1.go
注意📢:
- -o表示输出,s1.so 表示编译成so文件的名字,s1.go表示编译哪个go文件
- "-s -w" 选项用于减小生成动态链接库的体积,-s 是压缩,-w 是去掉调试信息
go build -ldflags "-s -w" -o main.dll -buildmode=c-shared s1.go
- 编译模式buildmode:
使用 Python 语言调用
from ctypes import cdll
lib = cdll.LoadLibrary('./s1.so')
# 调用go语言的Sum
result = lib.Sum(100, 200)
print(result)
最后
Python 和 GO 之间的参数传递需要经过 C 的疏忽类型转换,所以还需要了解 python 中 ctypes 数据类型和 python 数据类型以及 C 的数据类型对应关系
三种数据类型使用场景:
- ctypes数据类型为指定调用函数时的传入参数和返回值的数据类型
- python数据类型为调用函数时传入的参数的数据类型
- C的数据类型为go代码中定义的函数所需的参数和返回值数据类型
对应关系如下:
也就是说,如果写如下的 go 代码:
//export hello
func hello(namePtr *C.char){
name := C.GoString(namePtr)
log.Println("Hello", name)
}
也就意味着,我们的 Python 调用代码中参数类型也需要对应起来:
hello = library.hello
hello.argtypes = [ctypes.c_char_p]
hello("everyone".encode('utf-8'))
参考文章
前言
Python 可以通过 ctypes 模块调用 C 语言实现的函数,调用的方式很简单:
CDLL
的实例{CDLL_instance}.{function_name}({function_parameters})
格式调用 c 语言对应的函数步骤一
步骤二
使用下述命令,创建 so 文件
步骤三&四
调用 C 的函数
调用 GO 代码
从上面的 C 语言的调用过程,不难发现,最重要的是生成的
.so
文件,如果我们可以将 go 编辑成.so
文件就可以得到 Python 调用 Go 的目的了。CGO
Go 有个标准库 CGO 可以用来创建调用 C 代码的 Go 包,当然反过来也可以。
例子
需要注意的是:
编译动态库
使用下面的命令进行编译
注意📢:
go build -ldflags "-s -w" -o main.dll -buildmode=c-shared s1.go
使用 Python 语言调用
最后
Python 和 GO 之间的参数传递需要经过 C 的疏忽类型转换,所以还需要了解 python 中 ctypes 数据类型和 python 数据类型以及 C 的数据类型对应关系
三种数据类型使用场景:
对应关系如下:
也就是说,如果写如下的 go 代码:
也就意味着,我们的 Python 调用代码中参数类型也需要对应起来:
参考文章