使用C写Python的模块

2023-11-05

使用C写Python的模块

  • 2012-12-21 23:49 更新
  • 邹业盛
  1. 概述
  2. 引入 Python.h 头文件
  3. 编写包装函数
  4. 处理从 Python 传入的参数
  5. 实现逻辑功能
  6. 处理 C 中的返回值
  7. 注册函数
  8. 注册模块
  9. 编译

原文发于2010年11月。

1. 概述

Python 可以非常方便地和 C 进行相互的调用。

一般,我们不会使用 C 去直接编写一个 Python 的模块。通常的情景是,我们需要把 C 的相关模块包装一下,然后在 Python 中可以直接调用它。或者是,把 Python 逻辑中的某一效率要求很高的部分使用 C 来实现。整个过程大概是:

  1. 引入 Python.h 头文件。
  2. 编写包装函数。
  3. 函数中处理从 Python 传入的参数。
  4. 实现功能逻辑。
  5. 处理 C 中的返回值,包装成 Python 对象。
  6. 在一个 PyMethodDef 结构体中注册需要的函数。
  7. 在一个初始化方法中注册模块名。
  8. 把这个 C 源文件编译成链接库。
int add(int x, int y){
      return x + y;
  }
  
  //int main(void){
  //    printf("%d", add(1, 2));
  //    return 0;
  //}
  
  #include<Python.h>
  
  static PyObject* W_add(PyObject* self, PyObject* args){
      int x;
      int y;
      if(!PyArg_ParseTuple(args, "i|i", &x, &y)){
          return NULL;
      } else {
          return Py_BuildValue("i", add(x, y));
      }
  }
  
  static PyMethodDef ExtendMethods[] = {
      {"add", W_add, METH_VARARGS, "a function from C"},
      {NULL, NULL, 0, NULL},
  };
  
  PyMODINIT_FUNC initdemo(){
      Py_InitModule("demo", ExtendMethods);
  }

2. 引入 Python.h 头文件

这个文件一般位于 Python 的主目录中。比如我的 Ubuntu 10.04 下,它的位置在:

/usr/include/python2.6

在最后编译的时候指定目录就可以了。

3. 编写包装函数

因为 Python 用到的函数与普通的 C 函数,在输入和输出上,会有一些不同,所以,我们需要把普通的 C 做一些封来给 Python 用。

从另一方面来说,在实现功能的过程中,我们可以先完全不考虑这东西是拿给 Python 用的,只专注于使用 C 把它写好就可以了。最后,功能写好,测试没有问题之后,再做 Python 封装的工作。

包装函数一般声明成 static ,并且第一个参数是一个默认传入的 Python 对象,就是 Python 中某个对象的属性方法一样,第二个参数才是我们调用时传入的参数(实际上它是一个序列化后的字符串):

static PyObject* W_add(PyObject* self, PyObject* args);

4. 处理从 Python 传入的参数

因为我们的相关函数,之后是在 Python 环境中被调用的,那么它显然接受的就是从 Python 环境下传入的参数。这和 C 中你看到的函数是不同的,在 Python 的世界中,一切都是对象。所以,包装函数中首先要处理的问题就是解析从 Python 占获取的参数。

常用的函数有: PyArg_ParseTuple

int x;
  int y;
  PyArg_ParseTuple(args, "i|i", &x, &y);

PyArg_ParseTuple 的作用是解析我们从 Python 中传入的 args 这个字符串,然后以我们规定的格式将解析结果放入指定变量的内存位。

i|i " 就表示要把传入的东西解析成两个整数,同样,还有 s 表示字符串等。

5. 实现逻辑功能

这部分没什么特别的,只需要在 C 中一样调用函数就可以了,相关变量我们已经在上一步处理过了。

add(x, y);

6. 处理 C 中的返回值

我们使用 C 完成了功能逻辑, C 中会产生一个返回值,要将这个值返回到我们之前调用函数的 Python 环境中,当然还需要经过一些处理才行。

常用的函数是: Py_BuildValue 。

return Py_BuildValue("i", add(x, y));

这个函数的用法和上一步中的 PyArg_ParseTuple 是一样的,它们过程相反。 Py_BuildValue 把 C 中的值按给定的格式格式化成 Python 需要的对象。这里注意一下,对于 W_add 这个函数,我们可是声明了它的返回类型为 PyObject* 的哦。

7. 注册函数

在上面的实现完成之后,就需要作导出的准备了。第一步,就是要在一个类型为 PyMethodDef 的结构体中注册我们需要导出到 Python 中的函数:

static PyMethodDef ExtendMethods[] = {
      {"add", W_add, METH_VARARGS, "a function from C"},
      {NULL, NULL, 0, NULL},
  }

这个结构体成员有四个函数:

  1. add " 导出后在 Pyhton 中可见的方法名。
  2. W_add 实际映射到 C 中的方法名。
  3. METH_VARARGS 表示传入方法的是普通参数,当然还可以处理关键词参数。
  4. 此方法的注释。

8. 注册模块

在注册了方法后,就要注册此模块了。方法是定义一个 init* 的函数:

PyMODINIT_FUNC initdemo(){
      Py_InitModule("demo", ExtendMethods);
  }

方法名必须是 init 加上模块名,然后调用 Py_InitModule 来注册模块,这个函数的第一个参数就是模块名,第二个参数是此模块中我们导出的方法,就是上一步我们定义的结构体。

9. 编译

最后一步就是编译了。没什么特别的,指定好 Python.h 头文件的位置就可以了:

gcc demo.c -I /usr/include/python2.6 -shared -o demo.so

当然,链接库的名字要和我们期望导出的模块名一致。

这样,你就可以在 Python 中使用 import 直接引入 demo 模块,然后调用它的 add 方法了:

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

使用C写Python的模块 的相关文章

随机推荐

  • logback不输出至文件_Logback日志使用详解

    Logback是由log4j创始人设计的一个开源日志组件 概述 Logback建立于三个主要类之上 日志记录器 Logger 输出端 Appender 和日志格式化器 Layout 这三种组件协同工作 使开发者可以按照消息类型和级别来记录消
  • caffe 红绿灯识别

    coding utf 8 加载必要的库 import numpy as np import sys os 设置当前目录 caffe root home ubuntu caffe sys path insert 0 caffe root py
  • Report, 20150402, Formulas on Entropy, Part I

    Section 1 Papoulis s Formula Lemma 1 If the random variables y 1 ldots y n are the linear combination of random variable
  • Artifactory Maven 使用教程

    Maven 仓库使用 修改 Maven 配置文件 选择左侧 Artifacts 选择自己需要上传的 Maven 仓库 点击Set Me Up 在弹出的设置框中点击 点击下载生成的文件 将生成的文件放到此目录下 或者你自己的 Maven 目录
  • 线性回归模型

    线性回归是最简单的机器学习模型 也是最基础最重要的分析工具 易于实现 本文将将简单讲述线性回归 最小二乘法和梯度下降三种算法 目录 1 线性回归方程 OLS 2 最小二乘法 OLS 3 梯度下降 GD 3 1超参数 的选择 3 2局部最小值
  • Android使用OpenCV来实现bitmap独立设置每个圆角

    Android使用OpenCV来实现bitmap独立设置每个圆角 关于opencv集成请参考我的其他文章 这里方便起见已经封装成java方法供大家调用 代码如下 public static Bitmap drawCircleRadius i
  • 打乱1-100的个数字的顺序

    package test import java util Random public class Test2 public static void swap int a int i int j if a null a length 0 i
  • Weex页面的编写——Weex的学习之路(六)

    通过前几博客我们把weex的内置组件都学习完了 组件的单独使用想必都可以了 那么 这次我们来做weex实际页面的编写 见证一下 一套代码在Android Ios和H5上使用 在weex官网推荐我们使用Weex Studio作为编译器 其实这
  • Unity 3D作业二:离散仿真引擎基础

    前言 中山大学中山大学数据科学与计算机学院3D游戏课程学习记录博客 简答题 1 解释游戏对象 GameObjects 和资源 Assets 的区别与联系 游戏对象 出现在游戏场景中 充当游戏的组件 游戏对象不做任何事情 需要特殊属性才能成为
  • Xcode Executable Not Found

    问题 Xcode编译项目报Executable Not Found的错误 Details Details Executable Not Found Domain DVTMachOErrorDomain Code 5 Recovery Sug
  • Rust 删除排序数组中的重复项

    力扣https leetcode cn com problems remove duplicates from sorted array 参考代码和注释 fn main let mut v Vec
  • Linux下Elasticsearch离线安装

    先去下载离线安装包 我这里是7 10 0 Past Releases of Elastic Stack Software Elastic 上传到 usr local下 解压 tar zxvf elasticsearch 7 10 0 lin
  • 【MATLAB】MATLAB打开后,提示内部崩溃,直接闪退关闭——解决方法

    问题描述 在第一次安装MATLAB软件时 正常使用 过了一段时间后 突然发现在命令行可以正常使用 但运行编译文件里的程序便会报 MathWorks 崩溃的错误 提示MATLAB遇到了内部问题 需要关闭 结果MATLAB自己闪退结束 解决方法
  • MATLAB(6)GUI应用介绍

    目录 GUI编辑器 控件 属性 回调函数 MATLAB常见的控件 普通按钮 切换按钮 可编辑文本 字符获取 字符显示 复选框 单选按钮 弹出式菜单 滑动条 列表框 表 坐标区 附录 各文件共享数据 保存 获取 GUI编辑器 MATLAB的G
  • 【问题记录】05 Host key for [ip] has changed and you have requested strict checking.Host key verification

    1 报错信息如下 为主机ip WARNING REMOTE HOST IDENTIFICATION HAS CHANGED IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY Someo
  • 操作系统实验——互斥与同步

    目录 1 SYSTEM V信号量 1 创建或打开 semget 2 申请或释放 semop 3 设置信号量 semctl 2 POSIX信号量 1 初始化 sem init 2 申请和释放 sem wait 3 销毁 sem destroy
  • 详细记录YOLACT实例分割ncnn实现

    点击上方 AI算法修炼营 选择加星标或 置顶 标题以下 全是干货 整理 公众号 深度学习与计算机视觉 作者 nihui 链接 https zhuanlan zhihu com p 128974102 本文转载自知乎 作者已授权 未经许可请勿
  • 《写给大家看的设计书(第4版)》读书笔记

    文章目录 前言 设计原则 亲密性 对齐 重复 对比 结语 前言 设计类的书籍看过一些 大多分为两类 一类是讲基础的 构图 明暗 色彩等基础理论 还有一类是分享介绍具体案里的 这两类书籍对于大多数并不想真正成为设计师的人来说很多时候并没有什么
  • 位置无关码介绍

    1 基本概念 应用程序必须经过编译 汇编和链接后才变成可执行文件 在链接时 要对所有目标文件进行地址重定位 建立符号引用规则 同时为变量 函数等分配运行地址 当程序执行时 系统必须把代码加载到链接时所指定的地址空间即链接地址 链接地址介绍在
  • 使用C写Python的模块

    使用C写Python的模块 2012 12 21 23 49 更新 邹业盛 概述 引入 Python h 头文件 编写包装函数 处理从 Python 传入的参数 实现逻辑功能 处理 C 中的返回值 注册函数 注册模块 编译 原文发于2010