在python中扩展c语言模块

有一个以前写的c语言代码,我想把它用在python程序中。我先是看了《python基础教程》一书中的方法,书中说可以用swig加python内置distutils模块的方法来实现。我照着书上的步骤试了试,结果在导入模块的时候总是提示“ImportError:
dynamic module does not define init function (initprintf)”。起初我以为是so文件没有放对位置。但是我试着在目录中建立了一个简单的python模块,然后再导入,发现没有问题,看来python是可以直接导入当前目录下的模块的。接着我去网上找其他方法,发现网上少有人用swig,大多数都是自己写wrap文件实现。但是也有一个用swig的,其中的编译步骤跟书上的有差异。我就照着那个试了试,这次出了个新错误,“ImportError:
./example.so: undefined symbol: fact”。看来之前照书上来那个错误应该是因为so文件没有被放入指定位置造成的。接着我又开始想办法解决这个新错误,折腾了一会考虑到是不是没编译好,因此我就照着另一个网站的方法手动编译,问题终于得到了解决。解决方法来自ibm技术社区,看来还是这个网站靠谱。

就在刚刚我又重新试了试书上的方法。我发现swig是没有问题的,这个工具的作用就是把c源文件转换成用于python的接口源文件。之后我把之前生成的so文件改名,前边加上_,然后移入python的模块文件夹中,接着问题得到解决。看来swig的机制就是,生成的so文件必须以固定命名规则存入指定文件夹里,否则就会出问题。看来swig还是不够人性化啊。

接着我又开始试验用自己写wrap源文件配合distutils实现c扩展。但是还是会出现“ImportError:
./example.so: undefined symbol: fact”。这时我回想起自己用网上的编译教程时,有一步需要把原始的c文件也编译进去,我这才恍然大悟,distutils压根就没有编译过原始c文件,相关的函数怎么可能实现啊!于是我研究setup.py发现里面填源文件的地方是个list,应该可以填入多个源文件,所以我就把原始源文件也填了进去,果然问题得到了解决。

综上,在python中扩展c语言模块可以总结为以下几步:

  1. 首先,编写包含py接口的c源文件,称为wrap.c。这一步可以使用swig带过。 例如:swig
    -python foo.i
  2. 接着,对wrap.c进行编译,生成XX.so。这一步可以使用 distutils带过。如果要用 distutils的话,则需要首先编写一个py脚本。示例:setup(name
    = ‘example‘, version = ‘1.0‘, ext_modules = [Extension(‘example‘, [‘wrap.c‘,‘example.c‘])])  注意:句子中的list不仅不要包含wrap源文件,还要包含函数的原始源文件
  3. 上一步的so文件便是最终可以使用的库文件,把该文件放入py的lib中或者当前目录,即可导入c语言扩展模块进行使用。如果之前用过swig,还要把相应的so文件移入模块文件夹中并在文件名前加上_。示例:
    cp printf.so /usr/lib64/python2.7/site-packages/_printf.so

经过了之前的学习,我已经能够顺利的使用写好的wrap文件生成c扩展库了。今天我决定把自己的那些函数也都编译成扩展库。虽然我可以直接轻松的使用swig实现,但是swig要求必须把写好的库文件放入指定目录,否则就出问题,然而我想的是把所有需要的库都放入一个本地目录来方便程序的移植,swig显然跟我的想法相悖。因此我决定自己编写wrap文件。

wrap文件中有几个关键函数必须掌握。首先是:PyObject* wrap_fact(PyObject* self, PyObject* args)。这个函数的作用是分析python传进来的参数并执行响应的c函数。PyArg_ParseTuple(args, "is", &n,&c)函数可以用来分析python传进来的(元组)参数。其中的字符串参数是一个格式化字符串,里面is分别表示整形和字符串。后边需要加上存储参数的c变量地址,这里需要注意的是,这些参数必须是用来存储参数的变量的地址,即使要存储的是一个字符串也一样,这点·跟scanf还是有一定差异的。分析完参数之后,就可以直接利用得到的这些参数调用相应的c函数。之后可以利用return
Py_BuildValue("i", result)向python返回值。示意中语句可以将result变量的值以整形返回。总的来说,这个函数的实际作用就是取得python调用相应函数时所传递的参数,然后利用这些参数执行这个函数中的c代码段,然后将c代码段中的指定值返回给python。

然是是一个指针数组:static PyMethodDef exampleMethods[]。这个数组用来存储c函数映射表。每个c函数都需要有一个这样的{"fact", wrap_fact, METH_VARARGS, "Caculate N!"}数组,其中的元素依次代表python中函数的名字,接口函数地址,参数类型,函数描述。需要扩展多少个函数就要有多少个这样的数组。

最后是模块初始化函数:void initexample()。注意这个函数的名字是有讲究的,必须是init模块名字。里边需要包含语句:m = Py_InitModule("example", exampleMethods);其中的参数分别代表模块名字、函数映射表数组。

示例:

#include <Python.h>
extern int sendsyslog(const char *addr,int port,int type);
extern int sendtoac2(int type);
extern int sendtoac1(int type);
extern int rarecv(int wtime,const char *if_name2);
PyObject* sendcmsg_syslog(PyObject* self, PyObject* args)
{
  int port,type, result;
  char *addr;
  if (! PyArg_ParseTuple(args, "sii", &addr,&port,&type))
    return NULL;
  result = sendsyslog(addr,port,type);
  return Py_BuildValue("i", result);
}
PyObject* sendcmsg_sendac1(PyObject* self, PyObject* args)
{
  int type, result;
  if (! PyArg_ParseTuple(args, "i", &type))
    return NULL;
  result = sendtoac1(type);
  return Py_BuildValue("i", result);
}

static PyMethodDef sendcmsgMethods[] =
{
  {"syslog", sendcmsg_syslog, METH_VARARGS, "send syslog msg!"},
  {"sendac1", sendcmsg_sendac1, METH_VARARGS ,"send a q msg to client1"},
  {"sendac2", sendcmsg_sendac2, METH_VARARGS ,"send a q msg to client2"},
  {"rarecv", sendcmsg_rarecv, METH_VARARGS ,"detect ra msg"},
  {NULL, NULL}
};
void initsendcmsg()
{
  PyObject* m;
  m = Py_InitModule("sendcmsg", sendcmsgMethods);

}

在python中扩展c语言模块

时间: 2024-12-17 20:55:22

在python中扩展c语言模块的相关文章

python中的堆排序peapq模块

heapq模块实现了python中的堆排序,并提供了有关方法.让用Python实现排序算法有了简单快捷的方式. heapq的官方文档和源码:8.4.heapq-Heap queue algorithm 下面通过举例的方式说明heapq的应用方法 实现堆排序 #! /usr/bin/evn python #coding:utf-8 from heapq import * def heapsort(iterable): h = [] for value in iterable: heappush(h

python中根据字符串导入模块module

python中根据字符串导入模块module 需要导入importlib,使用其中的import_module方法 import importlib modname = 'datetime' datetime_module = importlib.import_module(modname) print(datetime_module) # <module 'datetime' from 'C:\\Users\\huchengyue\\AppData\\Local\\Programs\\Pyth

python中time、datetime模块的使用

目录 python中time.datetime模块的使用 1.前言 2.time模块 1.时间格式转换图 2.常用方法 3.datetime模块 python中time.datetime模块的使用 1.前言 如果您从事过python web的开发,那一定有过这样的经历,对于各种复杂繁琐的业务逻辑,掺杂着各种各样的时间约束,让人很容易搞的头晕眼花,比如展示出一天内用户进行过的所有操作记录,再比如进行验证码验证时获取当前时间与验证码生成时间进行比较,检查是否超过10分钟过期时间之类.这些关于时间的业

Python中正则表达式(re模块)的使用

1.正则表达式的概述 (1)概述:正则表达式是一些由字符和特殊符号组成的字符串,他们描述了模式的重复或者表示多个字符,正则表达式能按照某种模式匹配一系列有相似特征的字符串.正则表达式是一种小型的.高度的专业化的编程语言, (2)Python语言中的正则表达式内嵌在Python中通过re模块实现,正则表达式被编译成一系列的字节码,然后由C编写的匹配引擎执行 2.字符匹配 (1)符号匹配 符号 描述 示例 实例说明 literal 匹配文本字符串的字面值literal root 匹配字符串root

python中使用time时间模块

目的:学习python中time模块,可以获取当前时间或时间段 环境:ubuntu 16.04  python3.5.2 time模块,为内置模块,可以用来获取当前时间.日期,还可以设置延迟或倒计时. 使用前需导入模块 import time 常用的方法有:sleep(), strftime(), ctime() sleep(t),设置t的数字,单位为秒,可以有小数点,理解为延迟执行的秒数. time.sleep(5) 等待5秒后继续执行下面的语句. strftime(''),格式输出当前时间,

Python中xlrd和xlwt模块使用方法

本文主要介绍python中如何使用xlrd.xlwt模块操作excel表格,其中xlrd是读excel,xlwt是写excel的库. 安装xlrd和xlwt模块 默认情况下python是没有xlrd和xlwt模块,需要自行安装.模块安装建议使用pip自动安装.安装方法参考<Python自动安装第三方模块> xlrd模块使用 测试使用excel文档名称为Demo.xlsx,内容如下: 代码如下: # -*- coding: utf-8 -*- import xlrd import xlwt fr

Python中的正则表达式-re模块

有时候我们需要模糊查找我们需要的字符串等值,这个时候需要用到正则表达式. 正则表达式的使用,在python中需要引入re包 import re 1.首先了解下正则表达式的常用语法 --单个字符 . 任意的一个字符 a|b 字符a或字符b [afg] a或者f或者g的一个字符 [0-4] 0-4范围内的一个字符 [a-f] a-f范围内的一个字符 [^a] 不是a的一个字符 \s 一个空格 \S 一个非空格 \d [0-9],即0-9的任意字符 \D [^0-9],即非0-9的任意字符 \w [0

Python 中使用R语言

Python与R属于面向对象的的语言,各具优劣,本文意在将python与R语言相结合,以充分利用两者的优势.因此,本文主要 探讨Python与R语言的基本配置要求,Python调用R语言的配置,R语言在python中的使用等几个方面.由于笔者时间有限,只能 一点点更新,望见谅. I,本文中python与R软件的基本配置 python与R语言同为免费的开源语言,这给我们免费使用并学习这两门语言带来了极大的方便. python anaconda3.5.1 , R 3.2.3,  fedora lin

当你在 python中 import不到模块的时候

在 python中 import sys print sys.path 看一看模块的 引用路径 ,再看一看你的 模块路径 在不在这里面 rpm -ql .....你的模块(package) 如果不存在,那么就在 /etc/profile最后一行加上 export PYTHONPATH=$PYTHONPATH:你那个包的 路径 完成后保存退出 输入 source /etc/profile 再打开新的终端,看看在python直接import那个包行不行