• 一个简单的注册c函数到python的包装器


    这几天继续研究了一下python,顺便看了一下如何注册c的函数到python,这方面网上的东西已经很多了,就不详细说明了。反正大概就是把要注册的函数写成

    PyObject* Fun(PyObject* self, PyObject* args)

    这样的形式,然后通过PyArg_ParseTuple从python中取出参数传递给c函数,然后通过Py_BuildValue把c函数的返回值返回给python。


    所以对于一个形式如 int DoFun(int)类型的c函数,我们需要做的就是

    PyObject* Fun(PyObject* self, PyObject* args)

    {

          int arg;

          PyArg_ParseTuple("i", &arg);


          int ret = DoFun(arg);


          return Py_BuildValue("i", ret);

    }


    如果只有一个两个函数那还好,万一函数很多,怎么办,难道我们要每个函数都这么写,我觉得这个工作量比较大,我是个懒惰的人(呵呵,通常程序员都是挺懒的),所以对于这种事情,我希望只通过一个函数RegFun就搞定了,就像我以前写的注册c函数到lua一样的。


    首先就是考虑一个调用函数,他具有如下的形式


    template<typename Ret, typename P1, typename Func, Func func>
    static PyObject* CallFun(PyObject* self, PyObject* args)
    {
        string strArgType;
        string strRetType;

        P1 p1;

        ParseType<P1>(strArgType);
        PyArg_ParseTuple(args, strArgType.c_str(), &p1);

        ParseType<Ret>(strRetType);
        Ret ret = func(p1);

        return Py_BuildValue(strRetType.c_str(), ret);
    }

    其中ParseType是根据不同的模板参数得到参数的类型表示,如ParseType<int>的话strArgType就会添加一个"i"到参数字串上面。

    如果写成上面的那种形式,那么我们对于任何形如 Ret (*pFun)(Param )类型的函数都能够注册给python了,当然,这里面的Ret和Pram必须得是一般类型,不支持类和结构,以及除了char*之外的指针。

    但是这样有一个问题,就是万一如果我们的函数返回值为void,我们就需要重新定义CallFun了
    内部结构如下:

        string strArgType;
        
        P1 p1;

        ParseType<P1>(strArgType);
        PyArg_ParseTuple(args, strArgType.c_str(), &p1);

        func(p1);

        return Py_BuildValue("");

    于是我们就需要对模板进行偏特化处理,也就是把Ret换成void,但是现在c++的编译器是不支持函数模板的偏特化的,只支持函数模板的重载。那么如何解决呢?我们可以定义一个注册类

    template<typename Ret>
    class CCallFun
    {
    public:

        template<typename P1, typename Func, Func func>
        static PyObject* CallFun(PyObject* self, PyObject* args)
        {
            string strArgType;
            string strRetType;

            P1 p1;

            ParseType<P1>(strArgType);
            PyArg_ParseTuple(args, strArgType.c_str(), &p1);

            ParseType<Ret>(strRetType);
            Ret ret = func(p1);

            return Py_BuildValue(strRetType.c_str(), ret);
        }
    };

    然后进行void的特化
    template<>
    class CCallFun<void>
    {
    public:
        template<typename P1, typename Func, Func func>
        static PyObject* CallFun(PyObject* self, PyObject* args)
        {
            string strArgType;
        
            P1 p1;

            ParseType<P1>(strArgType);
            PyArg_ParseTuple(args, strArgType.c_str(), &p1);

            func(p1);

            return Py_BuildValue("");
        }
    };

    那么对于函数int DoFun(int)和void DoFun1(int),他们对应的注册函数就分别为

    CCallFun<int>::CallFun<int, int(*)(int), &DoFun>;



    CCallFun<void>::CallFun<int, void(*)(int), &DoFun1>

    然后我们注册给python

    PyMethodDef PyMethod[3]
    {
    {"DoFun1", &CCallFun<int>::CallFun<int, int(*)(int), &DoFun>, METH_VARARGS},
    {"DoFun1", &CCallFun<void>::CallFun<int, void(*)(int), &DoFun1>, METH_VARARGS},
    {NULL, NULL},
    };

    PyImport_AddModule("wr")
    Py_InitModule("wr", PyMethod)

    然后我们在python里面
    import wr
    wr.DoFun(10)
    wr.DoFun1(11)

    这样就行了。

    具体的代码请参照

    http://code.google.com/p/tangliu/downloads/list

    里面的ScriptPython.rar,不过这个版本是在vc8.0下面写的,linux下面没有经过测试。

  • 相关阅读:
    RN8209校正软件开发心得(1)
    Chrome 31版本导出Excel问题
    ComBox选择
    网页设计的一般步骤
    .NET一套开发工具
    关于用sql语句实现一串数字位数不足在左侧补0的技巧
    python jieba模块详解
    python内置函数详细描述与实例演示
    Markdown的基本语法记录
    python configparser模块详解
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6313794.html
Copyright © 2020-2023  润新知