python粘性扩展_1. 使用 C 或 C++ 扩展 Python

2023-11-04

1.12.给扩展模块提供C API¶

很多扩展模块提供了新的函数和类型供Python使用,但有时扩展模块里的代码也可以被其他扩展模块使用。例如,一个扩展模块可以实现一个类型 "collection" 看起来是没有顺序的。就像是Python列表类型,拥有C API允许扩展模块来创建和维护列表,这个新的集合类型可以有一堆C函数用于给其他扩展模块直接使用。

开始看起来很简单:只需要编写函数(无需声明为 static ),提供恰当的头文件,以及C API的文档。实际上在所有扩展模块都是静态链接到Python解释器时也是可以正常工作的。当模块以共享库链接时,一个模块中的符号定义对另一个模块不可见。可见的细节依赖于操作系统,一些系统的Python解释器使用全局命名空间(例如Windows),有些则在链接时需要一个严格的已导入符号列表(一个例子是AIX),或者提供可选的不同策略(如Unix系列)。即便是符号是全局可见的,你要调用的模块也可能尚未加载。

可移植性需要不能对符号可见性做任何假设。这意味着扩展模块里的所有符号都应该声明为 static ,除了模块的初始化函数,来避免与其他扩展模块的命名冲突(在段落 模块方法表和初始化函数 中讨论) 。这意味着符号应该 必须 通过其他导出方式来供其他扩展模块访问。

Python提供了一个特别的机制来传递C级别信息(指针),从一个扩展模块到另一个:Capsules。一个Capsule是一个Python数据类型,会保存指针( void * )。Capsule只能通过其C API来创建和访问,但可以像其他Python对象一样的传递。通常,我们可以指定一个扩展模块命名空间的名字。其他扩展模块可以导入这个模块,获取这个名字的值,然后从Capsule获取指针。

Capsule可以用多种方式导出C API给扩展模块。每个函数可以用自己的Capsule,或者所有C API指针可以存储在一个数组里,数组地址再发布给Capsule。存储和获取指针也可以用多种方式,供客户端模块使用。

无论你选择哪个方法,正确地为你的 Capsule 命名都很重要。 函数 PyCapsule_New() 接受一个名称形参 (const char *);允许你传入一个 NULL 作为名称,但我们强烈建议你指定一个名称。 正确地命名的 Capsule 提供了一定程序的运行时类型安全;没有可行的方式能区分两个未命名的 Capsule。

通常来说,Capsule用于暴露C API,其名字应该遵循如下规范:

modulename.attributename

便利函数 PyCapsule_Import() 可以方便的载入通过Capsule提供的C API,仅在Capsule的名字匹配时。这个行为为C API用户提供了高度的确定性来载入正确的C API。

如下例子展示了将大部分负担交由导出模块作者的方法,适用于常用的库模块。其会存储所有C API指针(例子里只有一个)在 void 指针的数组里,并使其值变为Capsule。对应的模块头文件提供了宏来管理导入模块和获取C API指针;客户端模块只需要在访问C API前调用这个宏即可。

导出的模块修改自 spam 模块,来自 一个简单的例子 段落。函数 spam.system() 不会直接调用C库函数 system() ,但一个函数 PySpam_System() 会负责调用,当然现实中会更复杂些(例如添加 "spam" 到每个命令)。函数 PySpam_System() 也会导出给其他扩展模块。

函数 PySpam_System() 是个纯C函数,声明 static 就像其他地方那样:

static int

PySpam_System(const char *command)

{

return system(command);

}

函数 spam_system() 按照如下方式修改:

static PyObject *

spam_system(PyObject *self, PyObject *args)

{

const char *command;

int sts;

if (!PyArg_ParseTuple(args, "s", &command))

return NULL;

sts = PySpam_System(command);

return PyLong_FromLong(sts);

}

在模块开头,在此行后:

#include

添加另外两行:

#define SPAM_MODULE

#include "spammodule.h"

#define 用于告知头文件需要包含给导出的模块,而不是客户端模块。最终,模块的初始化函数必须负责初始化C API指针数组:

PyMODINIT_FUNC

PyInit_spam(void)

{

PyObject *m;

static void *PySpam_API[PySpam_API_pointers];

PyObject *c_api_object;

m = PyModule_Create(&spammodule);

if (m == NULL)

return NULL;

/* Initialize the C API pointer array */

PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;

/* Create a Capsule containing the API pointer array's address */

c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL);

if (PyModule_AddObject(m, "_C_API", c_api_object) < 0) {

Py_XDECREF(c_api_object);

Py_DECREF(m);

return NULL;

}

return m;

}

注意 PySpam_API 声明为 static ;此外指针数组会在 PyInit_spam() 结束后消失!

头文件 spammodule.h 里的一堆工作,看起来如下所示:

#ifndef Py_SPAMMODULE_H

#define Py_SPAMMODULE_H

#ifdef __cplusplus

extern "C" {

#endif

/* Header file for spammodule */

/* C API functions */

#define PySpam_System_NUM 0

#define PySpam_System_RETURN int

#define PySpam_System_PROTO (const char *command)

/* Total number of C API pointers */

#define PySpam_API_pointers 1

#ifdef SPAM_MODULE

/* This section is used when compiling spammodule.c */

static PySpam_System_RETURN PySpam_System PySpam_System_PROTO;

#else

/* This section is used in modules that use spammodule's API */

static void **PySpam_API;

#define PySpam_System \

(*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])

/* Return -1 on error, 0 on success.

* PyCapsule_Import will set an exception if there's an error.

*/

static int

import_spam(void)

{

PySpam_API = (void **)PyCapsule_Import("spam._C_API", 0);

return (PySpam_API != NULL) ? 0 : -1;

}

#endif

#ifdef __cplusplus

}

#endif

#endif/* !defined(Py_SPAMMODULE_H) */

客户端模块必须在其初始化函数里按顺序调用函数 import_spam() (或其他宏)才能访问函数 PySpam_System() 。

PyMODINIT_FUNC

PyInit_client(void)

{

PyObject *m;

m = PyModule_Create(&clientmodule);

if (m == NULL)

return NULL;

if (import_spam() < 0)

return NULL;

/* additional initialization can happen here */

return m;

}

这种方法的主要缺点是,文件 spammodule.h 过于复杂。当然,对每个要导出的函数,基本结构是相似的,所以只需要学习一次。

最后需要提醒的是Capsule提供了额外的功能,用于存储在Capsule里的指针的内存分配和释放。细节参考 Python/C API参考手册的章节 Capsule 对象 和Capsule的实现(在Python源码发行包的 Include/pycapsule.h 和 Objects/pycapsule.c )。

脚注

这个函数的接口已经在标准模块 os 里了,这里作为一个简单而直接的例子。

术语"借用"一个引用是不完全正确的:拥有者仍然有引用的拷贝。

检查引用计数至少为1 没有用 ,引用计数本身可以在已经释放的内存里,并有可能被其他对象所用。

当你使用 "旧式" 风格调用约定时,这些保证不成立,尽管这依旧存在于很多旧代码中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python粘性扩展_1. 使用 C 或 C++ 扩展 Python 的相关文章

  • 《UnityAPI.AnimatorStateInfo动画器状态信息》(Yanlz+Unity+SteamVR+云技术+5G+AI+VR云游戏+IsName+IsTag+tag+立钻哥哥++OK++)

    UnityAPI AnimatorStateInfo动画器状态信息 版本 作者 参与者 完成日期 备注 UnityAPI AnimatorStateInfo V01 1 0 严立钻 2020 07 02 UnityAPI AnimatorS
  • 数据结构-链栈的c++实现

    pragma once ifndef My Head H define My Head H include G code c myhead h endif My Head H template
  • 远心镜头的区别

    文章预览 前言 Introduction 物方远心镜头 Object Space Telecentric 像方远心镜头 Image Space Telecentric 双侧远心镜头 Bi Telecentric 总结 Summary 前言
  • Python VTK 球体贴图代码详解(二)

    效果 继昨天的柱体代码学习 之后尝试了一把球体并进行贴图 效果如下 代码 代码是在昨天柱体基础上修改成球体 并针对球体贴图多了两步 import vtk 柱体 生成一个球体 sphere vtk vtkSphereSource 半径 sph
  • 主动运维管理摆脱“救火式”运维局面

    云呐运维管理模块是以服务目录的形式提供IT服务的交付 用户可点击服务目录中的服务 创建请求流程 通过服务门户汇总所有服务请求 事件 问题 变更记录 分派服务任务 监督执行情况全面管控事件的生命周期 支持事件升级策略定义 提高运维人员的效率
  • Linux 中宝塔面板的 tomcat 重启弹窗一闪而过,但是并未启动tomcat的问题

    这几天不知道是项目出错的原因还是其他因素 我在部署项目的时候 好像在宝塔的tomcat管理界面 点击了停止 我本想暂停tomcat服务 之后想再次开启的时候 tomcat 的重启按钮 一点 基本就是瞬间成功 这肯定有问题 一般来说tomca
  • 高校软件工程期末复习——ICONIX

    ch01 软件工程危机 定义 软件在开发和维护过程中遇到的一系列严重的问题 含义 如何开发软件 如何维护数量不断膨胀的已有软件 原因 客户对软件需求的描述不精确 可能有遗漏 有二义性 有错误 在软件开发过程中 用户提出修改软件功能 界面 支
  • Cookie和Session是什么?它们的区别是什么?

    什么是Cookie Cookie实际上是一小段的文本信息 客户端请求服务器 如果服务器需要记录该用户状态 就使用response向客户端浏览器颁发一个Cookie 客户端会把Cookie保存起来 当浏览器再请求该网站时 浏览器把请求的网址连
  • 谷歌浏览器报错:NET::ERR_CERT_AUTHORITY_INVALID

    chrome net internals hsts
  • Vivado使用心得(六)Vivado ILA观察信号和调试过程

    先简单介绍一下ILA Integrated Logic Analyzer 生成方法 这里有两种办法完成Debug Core的配置和实现 方法一 mark debug综合选项 Set Up Debug设定ILA参数 1 在信号 reg或者wi
  • MV-YOLO翻译(2018年5月 CVPR论文)【原创】

    声明 作者翻译论文仅为学习 如有侵权请联系作者删除博文 谢谢 另 如有不当的地方 请各位大佬批评指正 谢谢 MV YOLO 通过语义目标检测实现运动矢量跟踪 原论文pdf下载地址 https arxiv org pdf 1805 00107
  • office2010 错误1706 解决办法

    office2010 错误1706 解决办法 问题描述 1 弹窗 无限弹窗 无限 困扰了我大概半年的问题 自从上次不小心删掉一些有关office2010的东西 导致网页中下载东西后总是弹窗 office2010 卸载出现 安装程序找不到Pr
  • 以太坊微支付通道原理与实现

    以太坊微支付通道原理与实现 线上直接转账需要一定的费用 如果存在大量小额交易的情况下 费用会变的难以承受 因而以太坊引入了微交易支付通道来解决这个问题 以太坊提供了一个票据支付方案 主要依赖于智能合约实现的一对多的账单系统 该账单系统大致上
  • 【超级无敌详细的韩顺平java笔记】从入门到精通---基本数据类型的转换

    1 自动类型转换 当Java程序在进行赋值或运算时 精度小的类型自动转换为精度大的数据类型 这个就是自动类型转换 数据类型按照精度 容量 大小排序为 注意和细节 1 有多种类型的数据混合运算时 系统首先自动将所有数据转换成容量最大的那种数据
  • kafka 配置部署

    本文以部署三台kafka broker 为例讲解 kafka版本为 kafka 2 9 2 0 8 1 1 运行环境为centos jdk版本为1 7以上 kafka依赖zookeeper 部署之前部署好zookeeper集群 1 获取ka
  • Linux中操作sqlite3、sqlite3数据c/c++接口编程与Windows和Linux中sqlite3库的制作(SQLite二)

    目录 一 linux操作sqlite3 1 可以像window下通过qtcreator编译 2 可以用gcc直接编译 1 要安装libreadline dev 2 在工程文件中添加 3 打开shell c 在最前面添加一行代码 3 直接用U
  • .net线程同步

    大家都晓得 NET中线程同步有以下几种方式 临界区 Critical Section 互斥量 Mutex 信号量 Semaphore 事件 Event 1 临界区 通过对多线程的串行化来访问公共资源或一段代码 速度快 适合控制数据访问 在任
  • element-ui的表单验证及自定义验证规则

    element ui是一个组件库 里面有很多项大家都会用到 其中的表单项验证时比较常用的 比如我们一个登录界面有以下的要求 手机号 必填 11位移动手机号 验证码 必填 6位数字 协议 必须勾选
  • 【NoteExpress】技巧与Error解决方案

    Error 插入文献出现 OLE error 800A01A8错 错误原因 未在源word wps文件插入文献时报错 解决方案 检查是否在源word wps文件中进行操作 点击 去除格式化 分别进行去除格式化 清除域代码操作 导入文献 出现

随机推荐

  • Java连接数据库(二):数据库连接池(druid)

    背景 每次使用SQL语句操作数据库的时候都需要创建一个与数据库的连接 使用完之后再把这个连接销毁掉 这种频繁创建与销毁比较耗费机器的性能跟资源 也没有太大意义 数据库连接可以解决该问题 备注 建立一个数据库连接是一件非常耗时 消耗时间 耗力
  • vue获取上传文件路径_VUE上传文件夹的三种解决方案

    1 背景 用户本地有一份txt或者csv文件 无论是从业务数据库导出 还是其他途径获取 当需要使用蚂蚁的大数据分析工具进行数据加工 挖掘和共创应用的时候 首先要将本地文件上传至ODPS 普通的小文件通过浏览器上传至服务器 做一层中转便可以实
  • 详解Arduino Uno开发板的引脚分配图及定义

    详解Arduino Uno开发板的引脚分配图及定义 在本篇文章中 我们将详细介绍Arduino开发板的硬件电路部分 具体来说 就是介绍Arduino Uno开发板的引脚分配图及定义 Arduino Uno微控制器采用的是Atmel的ATme
  • 【论文阅读】Learning Efficient Convolutional Networks through Network Slimming

    1 论文和代码 https arxiv org abs 1708 06519 https github com Eric mingjie network slimming 1 摘要 深度卷积神经网络 CNNs 在许多现实应用中的部署很大程度
  • 深入理解STL库

    关注本人公众号 获取更多学习资料 微信公众号搜索 阿Q正砖 上期说过C 这块面试问的东西也蛮多 简历上只要出现C 这几个字 那么STL库就是必问 总不能是面试官问你了解STL库吗 你尴尬的说这块不怎么熟悉 那这就 总的来说STL库这块也不是
  • Data modeling essentials

    数据库设计才是王道 1 Introduction 2 Normalization 3 ER图 4 Subtypes and Supertypes 5 Attributes and columns 6 Primary key 7 Extent
  • Java集合大总结——Collection集合

    Collection集合的整理 1 List Set Queue Map四者的区别 集合底层数据结构梳理 2 关于集合的的选用 2 1 为什么使用集合 3 List接口 3 1 ArrayList 和 Array 数组 的区别 3 1 Li
  • ubuntu20.04 pycharm 中文输入法冲突 无法输入中文

    升级了ubuntu20之后 全家桶装完 发觉pycharm总是卡死 无法关闭 只能重启 最后发觉是因为搜狗输入法的原因 没找到什么很好的解决方法 只能删除搜狗输入法 但是又出现了新的问题 ibus无法输入中文 每次只能输入三个中文 裂开 在
  • 蓝桥杯真题:修改数组

    1 暴力思路 include
  • linux两块硬盘挂载同一目录,LINUX能否挂载两个磁盘到一个目录节点

    Smart猫小萌 你所谓的目录节点是指什么 比如 mnt a 即两个都挂载到 mnt a上 理论上是可以挂载的 不过你只能使用后挂载的那个磁盘里的内容 你可以用mkdir p mnt tmp mount t tmpfs o size 20m
  • 电脑桌面的word文件丢失了怎么找回?7个解决方法!

    word作为日常办公的文字处理软件 能够满足用户的各种文档处理需求 而在电脑长期使用过程中 难免会因为各种原因导致word文件丢失 那么电脑桌面的word文件丢失了怎么找回呢 针对用户的这个疑惑 下面以win10电脑系统为例 小编就来跟大家
  • 未来五年NFV增长率将达55%

    市场研究机构ABI Research发布的最新数据显示 2017年 2022年期间 网络功能虚拟化软件市场增长率将达到55 同时网络功能虚拟化服务将增长50 同期的硬件支出将下降 在欧洲 整个市场预测期内的年均复合增长率将达到53 但北美地
  • 【git】Github 上的 markdown 文件怎么上传并显示图片?

    要在GitHub上的Markdown文件中上传图片 可以使用以下步骤 一 上传图像文件夹 将图片上传到GitHub仓库中 你可以在仓库中创建一个文件夹 专门用于存储图片 二 在Markdown文件中插入图片 在Markdown文件中插入图片
  • win mac 双系统 opencore 硬盘引导_奶白MacOS+WIN 10双系统主机安装记录

    暑假地时候就计划要组装一台MacOS WIN 10双系统纯白主机 折腾了三个月 终于完美完成了主机的安装 配置单 处理器 Intel i7 10700K 主板 七彩虹CVN Z490 GAMING FROZEN V20 显卡 影驰 RTX2
  • VMware虚拟机的配置与Linux的安装

    VMware虚拟机的配置与Linux的安装 在这里使用的是VMware15版本和CentOS 7 x86 64 Minimal VMware虚拟机压缩包以及CentOS 7 x86 64 Minimal需要的点击下载 下面我们进行VMwar
  • tomcat配置通过域名访问,并且不加端口和项目名称

    废话不多说 直接上代码 首先tomcat的路径 打开server xml并在
  • 前端课设 网页设计期末作业-静态网页(下载链接在文末)

    网页设计期末作业 网站详情如下图所示 点我下载 https mp csdn net mp download manage download UpDetailed
  • ch4_7 确认字符串中的重复子串

    leetcod 459 重复的子字符串 给定一个非空的字符串 s 检查是否可以通过由它的一个子串重复多次构成 示例 1 输入 s abab 输出 true 解释 可由子串 ab 重复两次构成 1 关键点分析 使用KMP 中构造出 最大相同前
  • 数据分析利器Jupyter notebook入门手册

    公众号 尤而小屋作者 Peter编辑 Peter 大家好 我是Peter 很多读者问过我 Peter文章中的Python代码都是用的什么编辑器写的 今天就公开啦 Jupyter Notebook 没有Pycharm 没有Vscode 没有S
  • python粘性扩展_1. 使用 C 或 C++ 扩展 Python

    1 12 给扩展模块提供C API 很多扩展模块提供了新的函数和类型供Python使用 但有时扩展模块里的代码也可以被其他扩展模块使用 例如 一个扩展模块可以实现一个类型 collection 看起来是没有顺序的 就像是Python列表类型