pycxx是使用C++語(yǔ)言給python寫擴(kuò)展代碼的輔助庫(kù),他不像boost.python或者swig那樣封裝的很厚,
只是對(duì)python API的簡(jiǎn)單封裝,將python的C API組織成類的形式。
首先來(lái)看pycxx自帶模塊擴(kuò)展樣例:
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) { ... }
};
創(chuàng)建擴(kuò)展模塊的步驟如下:
1、從 template<class T> ExtensionModule模板類繼承,class T 實(shí)例為本類
2、構(gòu)造函數(shù)傳入模塊名 ExtensionModule<example_module>( "example" )
3、實(shí)現(xiàn)擴(kuò)展函數(shù),如實(shí)現(xiàn)了
Object ex_sum(const Tuple &a) { ... }
4、在構(gòu)造函數(shù)中加入擴(kuò)展函數(shù)
add_varargs_method("sum", &example_module::ex_sum,
"sum(arglist) = sum of arguments");
5、將擴(kuò)展模塊注冊(cè)到python中
initialize( "documentation for the example module" );
6、將模塊對(duì)象實(shí)例化,模塊屬于單一對(duì)象,給出的樣例是:
void initexample()
{
static example_module* example = new example_module;
}
將擴(kuò)展模塊注冊(cè)到python中靠這個(gè)initialize函數(shù)
void initialize( const char *module_doc="" )
{
//調(diào)用了基類的方法
ExtensionModuleBase::initialize( module_doc );
//....
}
//最終也就是調(diào)用了python的API注冊(cè)進(jìn)去了
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
);
}
可以看到注冊(cè)的時(shí)候傳入了m_method_table,是否這個(gè)加入擴(kuò)展函數(shù)的地方呢, 這里雖然可以加入,但實(shí)際上add_varargs_method
是加入到method_map_t,相當(dāng)于該類的靜態(tài)成員中。
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是類的成員函數(shù)指針,原型如下,這也是pycxx用模板的主要原因了。
typedef Object (T::*method_varargs_function_t)( const Tuple &args );
在initialize函數(shù)里,遍歷了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;
}
}
真正注冊(cè)到python中的函數(shù)其實(shí)是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函數(shù)實(shí)現(xiàn)如下,第一個(gè)參數(shù)_self_and_name_tuple就是上面的args,
args[0]是this指針,args[1]保存著MethodDefExt,里面有成員指向所調(diào)用的函數(shù)
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;
}
}
上述實(shí)現(xiàn)里又調(diào)用invoke_method_varargs,實(shí)現(xiàn)如下,這里ext_varargs_function就是真正調(diào)用的函數(shù)了,如注冊(cè)的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)
評(píng)論(2) 編輯 收藏 引用 所屬分類:
pycxx