通过 Python 可以直接调用动态库,通常有两种方式,使用 ctypes 进行封装,还可以对 C/C++ 库直接封装成动态库,这样可以直接使用。
这里不再介绍 ctypes 的相关使用,详细介绍下如何直接使用动态库。
示例
除了性能之外,主要还是可以复用之前的代码,这里直接上示例。
#include <Python.h>
// define the function.
static PyObject *hello(PyObject *self, PyObject *args) {
printf("Hello World!!!\n");
return PyLong_FromLong(0);
}
// register the function.
static PyMethodDef foobar_methods[] = {
{"hello", hello, METH_NOARGS, "show a greeting"},
{NULL, NULL, 0, NULL}
};
// register the module.
static struct PyModuleDef foobar_module = {
PyModuleDef_HEAD_INIT,
"foobar",
NULL,
-1,
foobar_methods
};
// init the module.
PyMODINIT_FUNC PyInit_foobar(void) {
return PyModule_Create(&foobar_module);
}
可以通过如下命令进行编译。
gcc -Wall -shared -std=c99 -fPIC \
$(python3-config --includes) $(python3-config --ldflags) \
foobar.c -o foobar$(python3-config --extension-suffix)
这样,在交互程序中可以通过如下方式使用。
$ python
>>> import foobar
>>> foobar.hello();
Hello World!!!
当然,也可以添加 setup.py
文件。
from distutils.core import setup, Extension
def main():
setup(
name="foobar",
version="1.0.0",
description="Python C API example",
author="Author Info",
ext_modules=[Extension("foobar", ["foobar.c"])]
)
if __name__ == "__main__":
main()
然后通过 python setup.py build
进行编译,会在 build
目录下生成对应的二进制文件。
函数定义
对函数的要求:
- 如果没有报错应该返回值,可以是
PyLong_FromLong()
、Py_BuildValue()
实现。 - 出现异常时,可以设置错误信息,然后返回
NULL
即可。
常用函数
解析参数返回值
int PyArg_ParseTuple(PyObject *args, char *format, ...);
其中,第一个参数是 args
指针,第二个参数则是用来指定参数的类型,如下仅列举部分:
Format Code | Python Type | C/C++ Type |
---|---|---|
s | str | char * |
z | str/None | char */NULL |
i | int | int |
l | long | long |
c | str | char |
d | float | double |
D | complex | Py_Complex * |
O | (any) | PyObject * |
S | str | PyStringObject * |
例如,通过如下方式解析一个字符串。
if (!PyArg_ParseTuple(args, "s", &message)) {
return NULL;
}
格式化格式内容同上,详细可以参考 Parsing arguments and building values 中的介绍。
PyObject *Py_BuildValue(const char *format, ...);
如下是简单的示例。
Py_BuildValue("") None
Py_BuildValue("i", 123) 123
Py_BuildValue("ii", 123, 456) (123, 456)
Py_BuildValue("s", "hello") "hello"
Py_BuildValue("ss", "hello", "world") ("hello", "world")
Py_BuildValue("s#", "hello", 4) "hell"
Py_BuildValue("()") ()
Py_BuildValue("(i)", 123) (123)
Py_BuildValue("(ii)", 123, 456) (123, 456)
Py_BuildValue("(i,i)", 123, 456) (123, 456)
Py_BuildValue("[i,i]", 123, 456) [123, 456]
Py_BuildValue("{s:i}", "key", 123) {"key": 123}
Py_BuildValue("((ii))(ii)", 1, 2, 3, 4) (((1, 2)), (3, 4))
参考
- 详细可以参考 MySQL Client 的实现。
- Python C API 官方文档。