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 阅读(2831)
评论(2) 编辑 收藏 引用 所属分类:
pycxx