以下为个人学习笔记整理
# 编写 Python 的 C 扩展
# 构建编译基础环境
- 启动 visual studio installer
 - 安装相关插件和依赖库
 

# 编写 C 扩展代码
简单的 C 扩展大致结构图:

- 定义函数: PyMethodDef
 - 定义模块: PyModuleDef
 - 定义初始化模块函数:PyInit_module
 
# 定义函数
函数名:
模块名_函数名参数类型
ml_flags:- METH_VARARGS :只包含元组参数 
def func(self, *args) - METH_VARARGS | METH_KEYWORDS :包含元组及字典参数 
def func(self, *args, **kwargs) - METH_FASTCALL :固定个数的元组参数。顾名思义,采用快速调用效率较高。 
def func(self, arg1, arg2, argN) - METH_FASTCALL | METH_KEYWORDS :固定个数元组参数 + 字典参数。 
def func(self, arg1, arg2, argN, **kwargs) - METH_NOARGS :无参函数。 
def func(self) - METH_O :单个参数。 
def func(self, arg1) - METH_CLASS :类函数。 
def func(cls) - METH_STATIC :静态函数。 
def func() 
- METH_VARARGS :只包含元组参数 
 逻辑代码
参数解析(PyArg_Parse):
PyArg_ParseTuple :解析位置参数。
PyArg_ParseTuple(PyObject* args, const char* format, ...)
int i,j;
char *s;
PyArg_ParseTuple(args,"iis", &i, &j, &s)
// Python call:func(i:int, j:int, s:str)PyArg_VaParse:用于解析可变数量参数,通过
var_list承载。PyArg_VaParse(PyObject* args, const char* format, va_list vargs)。- 相关使用案例
 
PyArg_ParseTupleAndKeywords:解析位置和关键字参数。
PyArg_ParseTupleAndKeywords(PyObject* args, PyObject* kw, const char* format, char* keywords[], ...)
char *a;
char *b;
char *foo = NULL;
char *bar = NULL;
char *baz = NULL;
static char *keywords[] = {"a","b","foo","bar","baz", NULL};
PyArg_ParseTupleAndKeywords(args, kwargs,"ss|sss", keywords, &a, &b, &foo, &bar, &baz)
// Python call:// func() // Fails, require a and b// func('a') // fails, requires b// func('a', 'b')// func('a', 'b', foo='foo', bar='bar', baz='baz)// func('a', 'b','foo', 'bar', 'baz')// func(a='a', b='b', foo='foo', bar='bar', baz='baz')PyArg_VaParseTupleAndKeywords :解析可变数量参数和关键字参数。
PyArg_VaParseTupleAndKeywords(PyObject* args, PyObject* kw, const char* format, char* keywords[], va_list vargs)
PyArg_ValidateKeywordArguments :解析关键字参数,关键字必须为字符串
PyArg_ValidateKeywordArguments(PyObject* kw)
PyArg_UnpackTuple :解析特定长度范围的元组。
PyArg_UnpackTuple(PyObject* args, const char* name, Py_ssize_t* min, Py_ssize_t* max, ...)
返回值 ——
Py_BuildValue:PyObject *Py_BuildValue(const char *format, ...)
Py_BuildValue("") None
Py_BuildValue("i", 123) 123
Py_BuildValue("iii", 123, 456, 789) (123, 456, 789)
Py_BuildValue("s", "hello") 'hello'
Py_BuildValue("y", "hello") b'hello'
Py_BuildValue("ss", "hello", "world") ('hello', 'world')
Py_BuildValue("s#", "hello", 4) 'hell'
Py_BuildValue("y#", "hello", 4) b'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,s:i}", "abc", 123, "def", 456) {'abc': 123, 'def': 456}
Py_BuildValue("((ii)(ii)) (ii)", 1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))
format格式:
| 字符 | 类型 | 含义 | 
|---|---|---|
s | const char * | 字符串 | 
s* | Py_buffer | 生成的 C 字符串可能包含嵌入的 NULL 字节 | 
s# | const char *,int | 拆解出两个对象,一个 str,一个 len | 
z | const char * | 字符串或者 None | 
z* | Py_buffer | 生成的 C 字符串可能包含嵌入的 NULL 字节或者 None | 
z# | const char *,int | 拆解出两个对象,一个 str 或者 None,一个 len | 
y | const char * | 只读字节对象 | 
S | PyBytesObject * | python 的 bytes 对象 | 
Y | PyByteArrayObject * | Python 的 bytearray 对象 | 
b | int | 无符号整数 | 
B | int | 无符号整数且不进行溢出检查 | 
h | int | 短整型 | 
H | int | 不进行溢出检查的短整型 | 
i | int | 正常整数 | 
l | long int | C 的长整形 | 
c | char | 字符 | 
d | double | 双精度浮点 | 
f | float | 单精度浮点 | 
p | bool | bool 类型本质上还是 int | 
D | Py_complex * | 复数 | 
(...) | tuple | 序列 | 
[...] | list | 列表 | 
{...} | dict | 字典 | 
O | PyObject* | Python 对象,不修改其引用计数 | 
O& | convert+void* | 将 Python 对象转为 C。 C-obj = converter(py-obj, O&); | 
\| | 表示后续参数是可选的 i|s : 一个整数,一个字符串。字符串可选 | |
$ | 表示后续参数仅是关键字 | |
: | 格式单位列表到此结束;在错误消息中使用冒号后的字符串作为函数名 | |
; | 格式单位列表到此结束;分号后的字符串用作错误消息。 : 和 ; 相互排斥。 | 
# exmaple:
# 定义 Python 的 C 扩展
[ccore.c]  | |
# include <Python.h> | |
static PyObject* ccore_calc(PyObject* self){  | |
return Py_BuildValue("i",100);  | |
} | |
struct PyMethodDef module_methods[] = {  | |
{"calc",(PyCFunction)ccore_calc, METH_NOARGS, "这是一个简单测测试"},  | |
{NULL, NULL, 0, NULL}  | |
};  | |
static struct PyModuleDef modulemethod = {  | |
  PyModuleDef_HEAD_INIT, | |
"ccore", /* name of module */  | |
"A sample module", /* Doc string (may be NULL) */  | |
-1, /* Size of per-interpreter state or -1 */  | |
  module_methods       /* Method table */ | |
};  | |
PyMODINIT_FUNC PyInit_ccore(void)  | |
{ | |
return PyModule_Create(&modulemethod);  | |
} | 
[setup.py]  | |
from distutils.core import setup  | |
from distutils.extension import Extension  | |
setup(name='Py_ccore',  | |
version='1.0',  | |
ext_modules=[Extension('ccore', ['ccore.c'])],  | |
      ) | 
# 构建指令
python setup.py install | 
# 调用 Python 的 C 扩展
import ccore | |
print(ccore.calc())  | |
Out:100  | 
# 定义 PyMethodDef
- C 层的定义
 
struct PyMethodDef {  | |
char *ml_name;  | |
   PyCFunction ml_meth;  | |
int ml_flags;  | |
char *ml_doc;  | |
};  | 
| 字段 | 类型 | 含义 | 
|---|---|---|
ml_name | const char * | 函数名 | 
ml_meth | PyCFunction | 函数指针 | 
ml_flags | int | 参数类型 | 
ml_doc | const char * | 函数说明 | 
# C 层的使用:
struct PyMethodDef module_methods[] = {  | |
{"calc",(PyCFunction)ccore_calc, METH_NOARGS, "func.__doc__"},  | |
# ....  | |
{NULL, NULL, 0, NULL}  | |
};  | 
等价于定义了一个如下结构的函数,不包含实现和返回值
def calc():  | |
    """func.__doc__"""" | |
...  | 
# 定义 PyModuleDef
- C 层的定义
 
struct PyModuleDef {  | |
    PyModuleDef_HEAD_INIT, | |
char *m_name;  | |
char *m_doc;  | |
Py_ssize_t m_size; //。  | |
PyMethodDef * m_methods;  | |
} | 
| 字段 | 类型 | 含义 | 
|---|---|---|
m_base | PyModuleDef_Base | 始终将此成员初始化为 PyModuleDef_HEAD_INIT | 
m_name | const char * | 模块名 | 
m_doc | const char * | 模块说明 | 
m_size | Py_ssize_t | 设置存储模块, -1 表示全局状态,不支持子解释器。 更多详细信息,请参见 PEP 3121  | 
m_methods | PyMethodDef * | 函数列表指针 | 
# C 层的使用:
static struct PyModuleDef modulemethod = {  | |
  PyModuleDef_HEAD_INIT, | |
"ccore",  | |
"A sample module",  | |
-1,  | |
module_methods  | |
};  | 
等价于定义了一个如下结构的模块
[ccore.py]  | |
"""A sample module""" | |
def calc():  | |
    """func.__doc__"""" | |
...  | |
...  | 
# 定义初始化模块函数
如下代码定义模块的创建
PyMODINIT_FUNC PyInit_ccore(void) // PyInit_模块名  | |
{ | |
return PyModule_Create(&modulemethod); // modulemethod is PyModuleDef obj  | |
} | 
参考资料:
Python 官方手册