孤独明镜

菩提本无树,明镜亦非台,本来无一物,何处惹尘埃。

嗨,我是Dragon,一名全栈开发者。现居上海,就职于一家游戏开发公司。做过Linux/QT、WEB(PHP/Python)、游戏开发,目前主攻图形/图像方向,对数学、文学、哲学、摄影等非常的喜爱。


使用Python C扩展实现带参数的装饰器

一、带参数装饰器的Python实现

def deco(arg):
    def _deco(func):
        def __deco():
            print("before %s called [%s]." % (func.__name__, arg))
            func()
            print("  after %s called [%s]." % (func.__name__, arg))
        return __deco
    return _deco

@deco("mymodule")
def myfunc():
    print(" myfunc() called.")

二、使用Python扩展模仿上面的装饰器

#include <python.h>

static PyObject *MSError;
static PyObject *private_m;

/**********************************************************
* RouteDecorator()
* return: python func
**********************************************************/
static PyObject *RouteDecorator(PyObject *self, PyObject *args)
{
    PyObject *func = NULL;
    if (!PyArg_ParseTuple(args, "O", &func))
    {
        PyErr_SetString(MSError, "test arguments is not valid!");
        return Py_BuildValue("b", 0);
    }

    if (!PyCallable_Check(func))
    {
        printf("RouteDecorator:arguments is not a function!\n");
        return Py_BuildValue("b", 0);
    }

    if (func)
    {
        PyObject *arg = PyDict_New();
        PyObject *key = Py_BuildValue("s", "length");
        PyObject *value = Py_BuildValue("i", 0);
        PyDict_SetItem(arg, key, value);
        Py_DECREF(key);
        Py_DECREF(value);

        PyObject * argTuple = PyTuple_New(1);
        PyTuple_SetItem(argTuple, 0, arg);
        PyObject_CallObject(func, argTuple);
    }

    Py_INCREF(func);

    return func;
}

/**********************************************************
* Route()
* return: RouteDecorator func
**********************************************************/
static PyObject *Route(PyObject *self, PyObject *args)
{
    char *path = NULL;
    PyObject *callback = NULL;
    char *method = NULL;
    if (!PyArg_ParseTuple(args, "s|sO", &path, &method, &callback))
    {
        PyErr_SetString(MSError, "test arguments is not valid!");
        return Py_BuildValue("b", 0);
    }
    printf ("path:%s, method:%s\n", path, method);
    //Py_INCREF(path);
    Py_INCREF(callback);

    if (callback&&!PyCallable_Check(callback))
    {
        printf("second arguments is not a function!\n");
        return NULL;
    }

    if (callback)
    {
        PyObject_CallObject(callback, NULL);
    }

    PyObject *pFunc = PyObject_GetAttrString(private_m, "RouteDecorator");

    //Py_INCREF(pFunc);

    return pFunc;
} 

/**********************************************************
* register infomation for this modules
**********************************************************/
static PyMethodDef PrivateMethods[] = {
{"RouteDecorator",  RouteDecorator, METH_VARARGS, "RouteDecorator method."},
{NULL, NULL, 0, NULL}
};

static PyMethodDef NvidiaSettingMethods[] = {
{"Route",  Route, METH_VARARGS, "Route method."},
{NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initframeworktest(void)
{
    private_m = Py_InitModule("", PrivateMethods);

    PyObject *m = Py_InitModule("frameworktest", NvidiaSettingMethods);
    if (m == NULL)
        return;

    MSError = PyErr_NewException("frameworktest.error", NULL, NULL);
    Py_INCREF(MSError);

    PyModule_AddObject(m, "error", MSError);
}
</python.h>

使用Route获取python传递的参数,使用RouteDecorator获取要装饰的函数。
上面的扩展构建脚本如下:

#!/usr/bin/python2.7

from distutils.core import setup, Extension

module1 = Extension('frameworktest',
                    define_macros = [('MAJOR_VERSION', '1'),
                                     ('MINOR_VERSION', '0')],
                    sources = ['framework-test.c'])

setup (name = 'frameworktest',
    version = '1.0',
    description = 'This is frameworktest package',
    author = 'Ren Jihe',
    author_email = 'renjihe@renjihe.com',
    url = 'http://www.renjihe.com',
    ext_modules = [module1])

测试脚本:

#!/usr/bin/python2.7

#import frameworktest
from frameworktest import *

def func():
    print "func callback called!"

@Route("/", "POST", func)
def ddd(args):
    print "ddd called!"
    print args

if __name__ == "__main__":
    ddd("");

注意:扩展中private_m = Py_InitModule(“”, PrivateMethods);是将RouteDecorator函数放入一个模块中,可以在Route函数中通过PyObject *pFunc = PyObject_GetAttrString(private_m, “RouteDecorator”);找到这个扩展函数。

转载请注明地址:孤独明镜