使用 C 或 C++ 扩展 Python

如果你会用 C,添加新的 Python 内置模块会很简单。以下两件不能用 Python 直接做的事,可以通过 extension modules 来实现:实现新的内置对象类型;调用 C 的库函数和系统调用。

为了支持扩展,Python API(应用程序编程接口)定义了一系列函数、宏和变量,可以访问 Python 运行时系统的大部分内容。Python 的 API 可以通过在一个 C 源文件中引用 "Python.h" 头文件来使用。

扩展模块的编写方式取决与你的目的以及系统设置;下面章节会详细介绍。

备注

C扩展接口特指CPython,扩展模块无法在其他Python实现上工作。在大多数情况下,应该避免写C扩展,来保持可移植性。举个例子,如果你的用例调用了C库或系统调用,你应该考虑使用 ctypes 模块或 cffi 库,而不是自己写C代码。这些模块允许你写Python代码来接口C代码,而且可移植性更好。不知为何编译失败了。

1.1. 一个简单的例子

让我们创建一个扩展模块 spam (Monty Python 粉丝最喜欢的食物...) 并且想要创建对应 C 库函数 system() [1] 的 Python 接口。 这个函数接受一个以 null 结尾的字符串参数并返回一个整数。 我们希望可以在 Python 中以如下方式调用此函数:

>>>

复制代码
>>> import spam
>>> status = spam.system("ls -l")

首先创建一个 spammodule.c 文件。(传统上,如果一个模块叫 spam,则对应实现它的 C 文件叫 spammodule.c;如果这个模块名字非常长,比如 spammify,则这个模块的文件可以直接叫 spammify.c。)

文件中开始的两行是:

复制代码
#define PY_SSIZE_T_CLEAN
#include <Python.h>

这会导入 Python API(如果你喜欢,你可以在这里添加描述模块目标和版权信息的注释)。

备注

由于 Python 可能会定义一些能在某些系统上影响标准头文件的预处理器定义,因此在包含任何标准头文件之前,你 必须 先包含 Python.h

推荐总是在 Python.h 前定义 PY_SSIZE_T_CLEAN 。查看 提取扩展函数的参数 来了解这个宏的更多内容。

所有在 Python.h 中定义的用户可见的符号都具有 PyPY 前缀,已在标准头文件中定义的那些除外。 考虑到便利性,也由于其在 Python 解释器中被广泛使用,"Python.h" 还包含了一些标准头文件: <stdio.h><string.h><errno.h><stdlib.h>。 如果后面的头文件在你的系统上不存在,它还会直接声明函数 malloc()free()realloc()

下面添加C函数到扩展模块,当调用 spam.system(string) 时会做出响应,(我们稍后会看到调用):

复制代码
static PyObject *
spam_system(PyObject *self, PyObject *args)
{
    const char *command;
    int sts;

    if (!PyArg_ParseTuple(args, "s", &command))
        return NULL;
    sts = system(command);
    return PyLong_FromLong(sts);
}

有个直接翻译参数列表的方法(举个例子,单独的 "ls -l" )到要传递给C函数的参数。C函数总是有两个参数,通常名字是 selfargs

对模块级函数, self 参数指向模块对象;对于方法则指向对象实例。

args 参数是指向一个 Python 的 tuple 对象的指针,其中包含参数。 每个 tuple 项对应一个调用参数。 这些参数也全都是 Python 对象 --- 要在我们的 C 函数中使用它们就需要先将其转换为 C 值。 Python API 中的函数 PyArg_ParseTuple() 会检查参数类型并将其转换为 C 值。 它使用模板字符串确定需要的参数类型以及存储被转换的值的 C 变量类型。 细节将稍后说明。

PyArg_ParseTuple() 在所有参数都有正确类型且组成部分按顺序放在传递进来的地址里时,返回真(非零)。其在传入无效参数时返回假(零)。在后续例子里,还会抛出特定异常,使得调用的函数可以理解返回 NULL (也就是例子里所见)。

相关推荐
Uitwaaien543 分钟前
51 单片机矩阵键盘密码锁:原理、实现与应用
c++·单片机·嵌入式硬件·51单片机·课程设计
小唐C++36 分钟前
C++小病毒-1.0勒索
开发语言·c++·vscode·python·算法·c#·编辑器
北 染 星 辰1 小时前
Python网络自动化运维---用户交互模块
开发语言·python·自动化
codists1 小时前
《CPython Internals》阅读笔记:p336-p352
python
我们的五年1 小时前
【C语言学习】:C语言补充:转义字符,<<,>>操作符,IDE
c语言·开发语言·后端·学习
Golinie1 小时前
【C++高并发服务器WebServer】-2:exec函数簇、进程控制
linux·c++·webserver·高并发服务器
Мартин.1 小时前
[Meachines] [Easy] GoodGames SQLI+Flask SSTI+Docker逃逸权限提升
python·docker·flask
日日行不惧千万里2 小时前
如何用YOLOv8训练一个识别安全帽的模型?
python·yolo
课堂随想2 小时前
`std::make_shared` 无法直接用于单例模式,因为它需要访问构造函数,而构造函数通常是私有的
c++·单例模式
siy23332 小时前
【c语言日寄】Vs调试——新手向
c语言·开发语言·学习·算法