很久以前就想写一篇这方面的笔记,这次做一个客户端验的模块,服务器端是用C#写的DES3加密,还要用到Socket连接,实在不是一般的麻烦,懒人有懒办法,决定用Python脚本来实现这个功能,顺便翻出以前的代码。把问题总结一下。
总的说起来Python Embeded有几个步骤。
(1)初始化Python脚本运行环境
Py_Initialize();
(2) 脚本的编译
bytecode = Py_CompileString(script.c_str() , "active" , Py_file_input)
python有多种embeded的形式,我最喜欢的是用Py_CompileString来编译一个.py的脚本文件,这样有下面几个好处,引用方便,调试方便,灵活。
编译好后会返回一个PyObject* 的bytecode对象
要注意的是.py脚本的格式很重要,一定记得换行用Unix方式的,否则是不会编译通过的,我第一次时就找了很久才发现这个问题,还有一个要注意的问题是最好编一个调试版本的python的dll和库,这样便于发现问题。
(3)导入编译好的脚本
module=PyImport_ExecCodeModule("active",bytecode),这个过程是构造库的过程,运行完成之后就会把你要应用的Python库装入内存当中。
(4)从module中导出对象
dict = PyModule_GetDict( module )
导出对象表后你就可以按照你的需要使用你想用的python对象,这里常用的是类,方法,函数,我这里只用了最简单全局函数,用fun = PyDict_GetItemString( dict , "active" );得到想要使用的函数对象。
(5)调用Python函数
还剩下一个问题了,如何给调用的Python函数传递参数
python函数的参数是一个Tuple类型的值,通俗的理解就是名字和对象的列表,这样不管你传递多少参数,只要用一个Tuple类型就都解决了,代码如下
args = PyTuple_New( argsnum );
if( !args )
{
PyErr_Print();
assert(false);
}
for( i = 0 ; i < argsnum ; i++ )
{
value = PyString_FromString( strings[i] );
PyTuple_SetItem( args , i , value );
}
用PyString_FromString等类型转换函数就可以实现参数生成的过程了。
(6)调用函数,得到返回值
value = PyObject_CallObject( fun , args );
if(!value)
{
PyErr_Print();
assert(false);
}
value是PyObject用转换函数就可以得到C++类型的返回值了,到这儿一个完整的调用过程就结束了
(7)其它
调用结束后释放脚本运行环境Py_Finalize();
注意下面几个问题,PyObject*都是有引用计数的,看文档说明有些对象是要自己处理引用计数的用Py_DECREF来释放对象,一般说如是类new操作的对象都要释放对象,如果是通过query出来的对象一般不用释放。
时间有限,很多细节的东西没有办法写得很详细了,希望我的笔记能帮助做同样工作的程序员们。