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, , NULL},
}; PyMODINIT_FUNC initdemo(){
Py_InitModule("demo", ExtendMethods);
}

2. 引入 Python.h 头文件

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

   /usr/include/python2.

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

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, , 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)

Sample

  1 #include <string>
2 #include <iostream>
3 #include <Python.h>
4
5 //Python c api使用方法
6
7 using namespace std;
8
9 string GetPyFun(string s1,string s2)
10 {
11 // void Py_Initialize( )
12 //初始化Python解释器,在C++程序中使用其它Python/C API之前,必须调用此函数,如果调用失败,将产生一个致命的错误
13 Py_Initialize();
14
15 //定义变量
16 PyObject * pModule = NULL;
17 PyObject * pFunc = NULL;
18 PyObject * pArg = NULL;
19 PyObject * result;
20 char *resultStr = "";
21
22 //int PyRun_SimpleString( const char *command)
23 //直接执行一段Python代码,就好象是在__main__ 函数里面执行一样。
24 //PyRun_SimpleString("import sys");
25 //PyRun_SimpleString("sys.path.append('C:\\Documents and Settings\\Administrator\\My Documents\\Visual Studio 2005\\Projects\\hello\\hello')");
26
27 //PyObject* PyImport_ImportModule(char *name)
28 //导入一个Python模块,参数name可以是*.py文件的文件名。相当于Python内建函数__import__()
29 pModule =PyImport_ImportModule("hello");//这里是要调用的文件名
30
31 //PyObject* PyObject_GetAttrString(PyObject *o, char *attr_name)
32 //返回模块对象o中的attr_name属性或函数,相当于Python中表达式语句:o.attr_name
33 pFunc= PyObject_GetAttrString(pModule, "Hello");
34
35 //PyObject* Py_BuildValue( char *format, ...)
36 //format以tuple的形式指定,一个参数就是(i)
37 //构建一个参数列表,把C类型转换为Python对象,使Python可以使用C类型数据
38 pArg= Py_BuildValue("(s,s)", s1.c_str(),s2.c_str());
39
40 //pParm = PyTuple_New(2);
41 //PyTuple_SetItem(pParm, 0, Py_BuildValue("s", csEntity));
42 //PyTuple_SetItem(pParm, 1, Py_BuildValue("s", csEntity));
43
44 //PyObject* PyEval_CallObject(PyObject* pfunc, PyObject* pargs)
45 //用于调用Python函数
46 //此函数接受两个PyObject*形参
47 //pfunc是要被调用的Python函数,通常可由PyObject_GetAttrString获得
48 //pargs是函数的参数列表,通常可由Py_BuildValue获得
49 result = PyEval_CallObject(pFunc, pArg);
50
51 //int PyArg_Parse( PyObject *args, char *format, ...)
52 //解构Python数据为C的类型,这样C程序中才可以使用Python里的数据。
53 PyArg_Parse(result, "s", &resultStr);
54
55 //关闭Python解释器,释放解释器所占用的资源
56 Py_Finalize();
57 return resultStr;
58 }
59
60 int Walk(const string& s1,const string& s2)
61 {
62 // void Py_Initialize( )
63 //初始化Python解释器,在C++程序中使用其它Python/C API之前,必须调用此函数,如果调用失败,将产生一个致命的错误
64 Py_Initialize();
65
66 //定义变量
67 PyObject * pModule = NULL;
68 PyObject * pFunc = NULL;
69 PyObject * pArg = NULL;
70 PyObject * result;
71 int reVal = 0;
72
73 //int PyRun_SimpleString( const char *command)
74 //直接执行一段Python代码,就好象是在__main__ 函数里面执行一样。
75 //PyRun_SimpleString("import sys");
76 //PyRun_SimpleString("sys.path.append('C:\\Documents and Settings\\Administrator\\My Documents\\Visual Studio 2005\\Projects\\hello\\hello')");
77
78 //PyObject* PyImport_ImportModule(char *name)
79 //导入一个Python模块,参数name可以是*.py文件的文件名。相当于Python内建函数__import__()
80 pModule =PyImport_ImportModule("walkdir");//这里是要调用的文件名
81
82 //PyObject* PyObject_GetAttrString(PyObject *o, char *attr_name)
83 //返回模块对象o中的attr_name属性或函数,相当于Python中表达式语句:o.attr_name
84 pFunc= PyObject_GetAttrString(pModule, "list_dir");
85
86 //PyObject* Py_BuildValue( char *format, ...)
87 //format以tuple的形式指定,一个参数就是(i)
88 //构建一个参数列表,把C类型转换为Python对象,使Python可以使用C类型数据
89 pArg= Py_BuildValue("(s,s)", s1.c_str(),s2.c_str());
90
91 //pParm = PyTuple_New(2);
92 //PyTuple_SetItem(pParm, 0, Py_BuildValue("s", csEntity));
93 //PyTuple_SetItem(pParm, 1, Py_BuildValue("s", csEntity));
94
95 //PyObject* PyEval_CallObject(PyObject* pfunc, PyObject* pargs)
96 //用于调用Python函数
97 //此函数接受两个PyObject*形参
98 //pfunc是要被调用的Python函数,通常可由PyObject_GetAttrString获得
99 //pargs是函数的参数列表,通常可由Py_BuildValue获得
100 result = PyEval_CallObject(pFunc, pArg);
101
102 //int PyArg_Parse( PyObject *args, char *format, ...)
103 //解构Python数据为C的类型,这样C程序中才可以使用Python里的数据。
104 PyArg_Parse(result, "i", &reVal);
105
106 //关闭Python解释器,释放解释器所占用的资源
107 Py_Finalize();
108 return reVal;
109 }
110
111 int main()
112 {
113 //string re=GetPyFun("hello","world");
114 //cout<<"\n"<<re<<endl;
115
116 cout<<"enter a path and a filename:"<<endl;
117 string path,dir;
118 cin>>path>>dir;
119 int re=Walk(path,dir);
120
121 return 0;
122 }

Python:C语言扩展的更多相关文章

  1. C语言扩展Python模块

    1. 先创建一个PythonDemo.cpp文件: //c/c++中调用python脚本,配置步骤参见上一篇:C/C++与python交互 \  C/C++中调用python文件. #include ...

  2. python使用C扩展

    CPython还为开发者实现了一个有趣的特性,使用Python可以轻松调用C代码 开发者有三种方法可以在自己的Python代码中来调用C编写的函数-ctypes,SWIG,Python/C API.每 ...

  3. 使用C语言扩展Python3

    使用C语言扩展Python3.在Python3中正确调用C函数. 1. 文件demo.c #include <Python.h> // c function static PyObject ...

  4. Python和C扩展实现方法

    一.Python和C扩展 cPython是C编写的,python的扩展可以用C来写,也便于移植到C++. 编写的Python扩展,需要编译成一个.so的共享库. Python程序中. 官方文档:htt ...

  5. Azure Table storage 之改进DynamicTableEntity类为其添加动态语言扩展

    在之前的一篇文章中提到,storage类库中包含一个可以用来动态获取Azure table storage 表结构的类-DynamicTableEntity. 我们可以通过这个类,我们无需为每一个表提 ...

  6. javascript语言扩展:可迭代对象(3)

    除了前2篇文章中描述的可迭代对象以外,在js语言扩展中的生成器对象,也可以作为可迭代对象. 这里用到一个新的关键字yield,该关键字在函数内部使用,用法和return类似,返回函数中的一个值:yie ...

  7. Visual Studio 2013 编译 64 位 Python 的 C 扩展 (使用 PyObject 包装)

    对于 32 位 Python 的 C 扩展,以前用过 mingW32 编译, 但是 mingW32 不支持 64 位 Python 的 C 扩展编译,详情可见 stackoverflow,这位前辈的大 ...

  8. R语言扩展包dplyr——数据清洗和整理

    R语言扩展包dplyr——数据清洗和整理 标签: 数据R语言数据清洗数据整理 2015-01-22 18:04 7357人阅读 评论(0) 收藏 举报  分类: R Programming(11)  ...

  9. C#高级编程9-第12章 动态语言扩展

    C#高级编程9-第12章 动态语言扩展 dynamic t = new ExpandoObject(); t.Abc = "abc"; t.Value = ; Console.Wr ...

  10. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

随机推荐

  1. mongodb备忘

    1.远程拷贝数据库 db.copyDatabase(fromdb, todb, fromhost, [dbuser, dbpassword]) 2.数据库备份/恢复(导出/导入) mongoexpor ...

  2. redis与memcache的区别2

    总结一: memcache官方定义 Free & open source, high-performance, distributed memory object caching system ...

  3. Struts2基础学习总结

    引用自:http://www.cnblogs.com/jbelial/archive/2012/05/10/2486886.html Struts 2是在WebWork2基础发展而来的. 注意:str ...

  4. nginx服务器状态监控

    Nginx开启监控需在编译时加入with-http_stub_status_module,查看当前Nginx编译参数:/usr/local/nginx/sbin/nginx -V 1.以二级目录方式开 ...

  5. 【Git】安装以及第一次使用Git和GitHub傻瓜教程

    1.下载安装git(windows7) 下载git:https://www.git-scm.com/download/win 点击exe文件一路next就可以. 2.配置(参考:http://git. ...

  6. php判断闰年

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  7. Hadoop学习笔记(一)从官网下载安装包

    Hadoop是一个分布式系统基础架构,由Apache基金会所开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群的威力进行高速运算和存储.要学习Hadoop从下载安装包开始 打开 ...

  8. 实用命令dd

    1.命令简介 dd 的主要选项: 指定数字的地方若以下列字符结尾乘以相应的数字: b=512, c=1, k=1024, w=2, xm=number m if=file #输入文件名,缺省为标准输入 ...

  9. dede 数据库类使用列表

    dedecms的数据库操作类,非常实用,在二次开发中尤其重要,这个数据库操作类说明算是奉献给大家的小礼物了. 引入common.inc.php文件 require_once (dirname(__FI ...

  10. 全网扫描扫描10000端口后的优化脚本&域名列表指定端口的批量测试

    方法一: #coding=utf-8 import urllib2 import threading from time import ctime,sleep print "Start-Ti ...