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 閱讀(2907)
評論(2) 編輯 收藏 引用 所屬分類:
pycxx