巧用 python 腳本控制你的C程序(首發在個人博客園)

http://www.cnblogs.com/haippy/archive/2011/09/17/2179902.htmlhtml

python是一門藝術語言,除了開發桌面程序,還可以開發網絡應用,數據庫應用,還能夠代替shell編寫一些的實用腳本,本文主要講述瞭如何利用 python 程序控制你的 C 程序的行爲。python

做爲例子,本文將用 python 和 C 語言來編寫示例代碼,同時也會順便介紹一下 利用 C 語言擴展 python的方法,最後會給出完整的 C 編寫 python 模塊的源碼。linux

首先考慮如下應用:假設你須要在項目中實現字符串排序比較的功能,可是事先並不肯定應該如何排序(再次假設一下,若是某字符串中若是出現了 「aaa」, "bbb" 這樣的子串,就將該字符串排在靠後的位置),此時若是用 C 語言實現了預約義的排序功能,那麼萬一某天須要改變字符串排序行爲,就必須從新編寫 C 程序的實現,而且再次編譯項目,這樣會浪費大量的精力,相反,若是將字符串排序的功能用 python 代碼控制,即如何排序由python程序定義,這樣將大大提升程序的靈活性。shell

如下就是示例程序,程序由 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 <haipingf@gmail.com>
 *        Company:  ICT
 *
 * =====================================================================================
 */

#include <Python.h>

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

執行過程:ui

$ 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 "<stdin>", line 1, in <module>
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」 大。spa

若是使用 python 定義咱們常規的字母排序的比較函數,會看到以下執行結果:3d

>>> 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的一些有趣的特性和使用方法,請關注本博客後續文章。:-) 

相關文章
相關標籤/搜索