python是一门艺术语言,除了开发桌面程序,还能够开发网络应用,数据库应用,还可以代替shell编写一些的实用脚本,本文主要讲述了如何利用 python 程序控制你的 C 程序的行为。
作为例子,本文将用 python 和 C 语言来编写示例代码,同时也会顺便介绍一下 利用 C 语言扩展 python的方法,最后会给出完整的 C 编写 python 模块的源码。
首先考虑以下应用:假设你需要在项目中实现字符串排序比较的功能,但是事先并不确定应该如何排序(再次假设一下,如果某字符串中如果出现了 “aaa”, "bbb" 这样的子串,就将该字符串排在靠后的位置),此时如果用 C 语言实现了预定义的排序功能,那么万一某天需要改变字符串排序行为,就必须重新编写 C 程序的实现,并且再次编译项目,这样会浪费大量的精力,相反,如果将字符串排序的功能用 python 代码控制,即如何排序由python程序定义,这样将大大提高程序的灵活性。
以下就是示例程序,程序由 python 脚本和 C 编译的 python 模块组成,python 实现字符串比较功能,为了简化期间,本文只是先两个字符串大小的比较(用于说明 python控制程序行为已经足够),程序采用回调函数实现,完整代码如下:
python模块:
/*
* =====================================================================================
*
* Filename: ext.c
*
* Description:
*
* Version: 0.1.0
* Created: 09/16/2011 05:44:40 PM
* Revision: r1
* Compiler: gcc
*
* Author: Fu Haiping
* Company: ICT
*
* =====================================================================================
*/
#include
static PyObject *my_callback = NULL;
static PyObject *
_set_callback(PyObject *self, PyObject *args)
{
PyObject *result = NULL;
PyObject *temp;
if (PyArg_ParseTuple(args, "O", &temp)) {
if (!PyCallable_Check(temp)) {
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return NULL;
}
Py_XINCREF(temp); /* Add a reference to new callback */
Py_XDECREF(my_callback); /* Dispose of previous callback */
my_callback = temp; /* Remember new callback */
/* Boilerplate to return "None" */
Py_INCREF(Py_None);
result = Py_None;
}
return result;
}
static int _compare(const char *a, const char *b)
{
long ret;
PyObject *arglist;
PyObject * result = NULL;
arglist = Py_BuildValue("(ss)", a, b);
result = PyEval_CallObject(my_callback, arglist);
ret = PyInt_AsLong(result);
if (result == NULL)
return -1;
Py_DECREF(result);
return ret;
}
void compare(const char *a, const char *b)
{
if (_compare(a, b) > 0) {
printf("arg1 is greater than arg2\n");
} else if (_compare(a, b) < 0) {
printf("arg1 is NOT greater than arg2\n");
} else {
printf("arg1 is equal to arg2\n");
}
}
static PyObject* _compare_callback(PyObject *self, PyObject *args)
{
const char *a = NULL, *b = NULL;
if (!PyArg_ParseTuple(args, "ss", &a, &b)) {
return NULL;
}
compare(a, b);
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef
extMethods[] = {
{"setcmp", _set_callback, METH_VARARGS},
{"compare", _compare_callback, METH_VARARGS},
{NULL, NULL}
};
void initext()
{
Py_InitModule("ext", extMethods);
}
setup.py 文件:
from distutils.core import setup, Extension
module1 = Extension('ext',
sources = ['ext.c'])
setup (name = 'ext',
version = '1.0',
description = 'This is a demo package',
ext_modules = [module1])
执行过程:
$ python
Python 2.6.6 (r266:84292, Sep 15 2010, 15:52:39)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ext
>>> def compare(a, b):
... if (a > b):
... return -1
... if (a < b):
... return 1
... if (a ==b):
... return 0
...
>>> setcmp(compare)
Traceback (most recent call last):
File "", line 1, in
NameError: name 'setcmp' is not defined
>>> ext.setcmp(compare)
>>> ext.compare("aaa", "bbb")
arg1 is greater than arg2
>>>
上述执行过程中,我们利用了 pythoon 的 compare函数,该函数实现字符串的比较,如果 a > b, 返回 -1,a < b, 返回1, a == b, 返回0, 这和我们平常的比较方式相反,所以最后的结果中我们可以看到比较 "aaa", "bbb" 时,"aaa" 会比 “bbb” 大。
如果使用 python 定义我们常规的字母排序的比较函数,会看到如下执行结果:
>>> def compare_ex(a, b):
... if (a > b):
... return 1
... if (a < b):
... return -1
... if (a == b):
... return 0
...
>>> ext.setcmp(compare_ex)
>>> ext.compare("aaa", "bbb")
arg1 is NOT greater than arg2
此时,"aaa" 就比 "bbb" 小。
结论,以上只是一个小小的尝试,python的灵活性远远不止如此,Haippy会继续探索 python的一些有趣的特性和使用方法,请关注本博客后续文章。:-)