随笔 - 78  文章 - 58  trackbacks - 0
<2012年3月>
26272829123
45678910
11121314151617
18192021222324
25262728293031
1234567

常用链接

留言簿(9)

随笔分类

随笔档案

文章档案

相册

搜索

  •  

积分与排名

  • 积分 - 264123
  • 排名 - 85

最新评论

阅读排行榜

评论排行榜

pycxx是使用C++语言给python写扩展代码的辅助库,他不像boost.python或者swig那样封装的很厚,

只是对python API的简单封装,将python的C API组织成类的形式。

首先来看pycxx自带模块扩展样例:

class example_module : public ExtensionModule<example_module>

{

public:

    example_module()

    : ExtensionModule<example_module>( "example" )

    {

        add_varargs_method("sum", &example_module::ex_sum, 

"sum(arglist) = sum of arguments");

        add_varargs_method("test", &example_module::ex_test, 

"test(arglist) runs a test suite");

        initialize( "documentation for the example module" );

    }

    virtual ~example_module() {}

private:

    Object ex_sum(const Tuple &a) { ... }

    Object ex_test(const Tuple &a) { ... }

};

创建扩展模块的步骤如下:

1、从 template<class T> ExtensionModule模板类继承,class T 实例为本类

2、构造函数传入模块名 ExtensionModule<example_module>( "example" )

3、实现扩展函数,如实现了

   Object ex_sum(const Tuple &a) { ... }

4、在构造函数中加入扩展函数

   add_varargs_method("sum", &example_module::ex_sum, 

"sum(arglist) = sum of arguments");

5、将扩展模块注册到python中

   initialize( "documentation for the example module" );

6、将模块对象实例化,模块属于单一对象,给出的样例是:

void initexample()

{

    static example_module* example = new example_module;

}

 

将扩展模块注册到python中靠这个initialize函数

void initialize( const char *module_doc="" )

{

    //调用了基类的方法

    ExtensionModuleBase::initialize( module_doc );

    //....

}

//最终也就是调用了python的API注册进去了

void ExtensionModuleBase::initialize( const char *module_doc )

{

    PyObject *module_ptr = new ExtensionModuleBasePtr( this );

    Py_InitModule4

    (

    const_cast<char *>( m_module_name.c_str() ),    // name

    m_method_table.table(),                         // methods

    const_cast<char *>( module_doc ),               // docs

    module_ptr,                                     // pass to functions as "self"

    PYTHON_API_VERSION                              // API version

    );

}

 

可以看到注册的时候传入了m_method_table,是否这个加入扩展函数的地方呢, 这里虽然可以加入,但实际上add_varargs_method

是加入到method_map_t,相当于该类的静态成员中。

        static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" )

        {

            method_map_t &mm = methods();

            mm[ std::string( name ) ] = new MethodDefExt<T>( name, function, method_varargs_call_handler, doc );

        }

method_varargs_function_t是类的成员函数指针,原型如下,这也是pycxx用模板的主要原因了。

typedef Object (T::*method_varargs_function_t)( const Tuple &args );

 

在initialize函数里,遍历了method_map_t,加入到模板的dict中。

        void initialize( const char *module_doc="" )
        {
            ExtensionModuleBase::initialize( module_doc );
            Dict dict( moduleDictionary() );

            //
            // put each of the methods into the modules dictionary
            // so that we get called back at the function in T.
            //
            method_map_t &mm = methods();
            EXPLICIT_TYPENAME method_map_t::const_iterator i = mm.begin();
            EXPLICIT_TYPENAME method_map_t::const_iterator i_end = mm.end();
            for ( ; i != i_end; ++i )
            {
                MethodDefExt<T> *method_def = (*i).second;

                static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc );

                Tuple args( 2 );
                args[0] = Object( self );
                args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ) );

                PyObject *func = PyCFunction_New
                                    (
                                    &method_def->ext_meth_def,
                                    new_reference_to( args )
                                    );

                method_def->py_method = Object( func, true );

                dict[ (*i).first ] = method_def->py_method;
            }
        }

 

真正注册到python中的函数其实是method_varargs_call_handler,即下面的method_def->ext_meth_def

                Tuple args( 2 );
                args[0] = Object( self );
                args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ) );

                PyObject *func = PyCFunction_New
                                    (
                                    &method_def->ext_meth_def,
                                    new_reference_to( args )
                                    );

 

method_varargs_call_handler函数实现如下,第一个参数_self_and_name_tuple就是上面的args,

args[0]是this指针,args[1]保存着MethodDefExt,里面有成员指向所调用的函数

extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args )
{
    try
    {
        Tuple self_and_name_tuple( _self_and_name_tuple );

        PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
        void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject );
        if( self_as_void == NULL )
            return NULL;

        ExtensionModuleBase *self = static_cast<ExtensionModuleBase *>( self_as_void );
        Tuple args( _args );

        Object result
                (
                self->invoke_method_varargs
                    (
                    PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ),
                    args
                    )
                );

        return new_reference_to( result.ptr() );
    }
    catch( Exception & )
    {
        return 0;
    }
}

上述实现里又调用invoke_method_varargs,实现如下,这里ext_varargs_function就是真正调用的函数了,如注册的ex_sum

        virtual Object invoke_method_varargs( void *method_def, const Tuple &args )
        {
            // cast up to the derived class, method_def and call
            T *self = static_cast<T *>( this );
            MethodDefExt<T> *meth_def = reinterpret_cast<MethodDefExt<T> *>( method_def );

            return (self->*meth_def->ext_varargs_function)( args );
        }

 

posted on 2012-03-01 20:59 merlinfang 阅读(2124) 评论(2)  编辑 收藏 引用 所属分类: pycxx

FeedBack:
# re: pycxx 源码分析-- 创建python扩展模块(1) 2012-03-01 23:48 dos命令大全
表示对py一窍不通  回复  更多评论
  
# re: pycxx 源码分析-- 创建python扩展模块(1) 2012-03-02 09:00 tb
分析得不错  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理