|
|
|
|
 [精华] 在c中嵌入python(1) - rings [ 2004-04-18 14:04 | 6,762 byte(s)]
 Re: 在c中嵌入python(1) - hoxide [ 2004-05-13 20:13 | 159 byte(s)]
 Re: 在c中嵌入python(1) - limodou [ 2004-05-14 13:22 | 217 byte(s)]
 Re: 在c中嵌入python(1) - gxcooo [ 2004-05-14 19:55 | 44 byte(s)]
 Re: 在c中嵌入python(1) - oyster [ 2004-05-14 23:53 | 100 byte(s)]
 Re: 在c中嵌入python(1) - rings [ 2004-05-13 20:26 | 23 byte(s)]
|
|
|
|
[Original]
[Print]
[Top]
|
在c中嵌入python
我们可以在c中嵌入python的调用。来执行python的命令或者脚本。我们先看
一个最简单的例子
#include <Python.h>
int
main(int argc, char *argv[])
{
Py_Initialize();
PyRun_SimpleString("from time import time,ctime
"
"print 'Today is',ctime(time())
");
Py_Finalize();
return 0;
}
这段c代码的执行其实就是调用python的:
"from time import time,ctime"
print 'Today is',ctime(time())
所有的python调用都必须在Py_Initialize()和Py_Finalize()之间。这个
好比在c中调用汇编一样
__asm // __asm block
{
mov eax, 01h
int 10h
}
PyRun_SimpleString是python的一个api,他的原型是
int PyRun_SimpleString( char *command)
他在__main__模块中来执行command。这个是最简单的执行python
调用的一种方式。
在嵌入python的调用中,其实我们主要是先把一些数据从c的表示形式转化成
python的表示形式。 比如, PyString_FromString,就是将一个c的字符串转化
成python的表示。然后调用python的API, 因为python的api的参数都是python的
表示形式。最后, 把python的调用结果转化成c的表示形式
在看一个复杂的调用。在python中,我们想调用math 模块的sqrt来做开方运算。一般
都要这么几个步骤。
1。 导入math模块
import math
2. 调用sqrt
>>>math.sqrt(16)
4.0
如果我们想在c中调用,也需要同样的步骤,不过只是我们是用c来做的。而且要加上
数据类型的转换。看一个例子。他其实就是做我们在python的工作
如果这个程序编译成test.exe, 那么他的调用形式应该是:
test.exe math sqrt 16
////////////////////////////////////////////////////////////
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
int i;
//先检查参数的个数。第一个参数是这个程序的名字, 在这里是vtest.exe
//第二个参数是模块的名字,第三个参数是这个模块里函数的名字
//后面的参数是调用这个函数的参数
//
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]
");
return 1;
}
Py_Initialize();
//获得第二个参数。argv[1]。他是模块的名字
pName = PyString_FromString(argv[1]);
/* Error checking of pName left out */
//导入模块, 例如import math. pName是传入的第二个参数。
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
//得到模块的__dict__。 相当于在python里调用
//math.__dict__
pDict = PyModule_GetDict(pModule);
/* pDict is a borrowed reference */
//在这个字典里找到我们要找的函数名字。函数名字是argv[2]
//在python里,相当于math.__dict__["sqrt"], 他返回的是个
//函数对象
pFunc = PyDict_GetItemString(pDict, argv[2]);
/* pFun: Borrowed reference */
//解析剩下的参数。这些参数是要传给我们要调用函数的参数。
//他们的数目是不定的。所以把他们存入到一个列表里
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(argc - 3); //构造一个Tuple, 长度是argc - 3
for (i = 0; i < argc - 3; ++i) { //做循环把剩余的参数设置到这个tuplp里
pValue = PyInt_FromLong(atoi(argv[i + 3])); //把c的类型转换成python的类型
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument
");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue); //设置这个值到tuple里。
}
pValue = PyObject_CallObject(pFunc, pArgs); //调用函数pFunc是函数名字, pArgs 是参数。
Py_DECREF(pArgs);
if (pValue != NULL) { //调用成功,打印一条信息
printf("Result of call: %ld
", PyInt_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pModule); //没有调用成功,打印错误的原因
PyErr_Print();
fprintf(stderr,"Call failed
");
return 1;
}
/* pDict and pFunc are borrowed and must not be Py_DECREF-ed */
}
else {
if (PyErr_Occurred())//检查到是否有错误发生
PyErr_Print();
fprintf(stderr, "Cannot find function "%s"
", argv[2]);
}
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load "%s"
", argv[1]);
return 1;
}
Py_Finalize();
return 0;
}
以test.exe math sqrt 16 作为一个例子
整个的流程是这样的。
1. 解析参数, test.exe 是argv[0]. math 是argv[1] sqrt 是argv[2]
剩下的参数个数是argc -3. argc 在这里是4, 剩下一个参数。
构造一个tuple, 把16设置到这个tuple中。
2.调用sqrt(16). 使用PyObject_CallObject。 第一个参数是找个函数对象,
第二个是存入剩余参数的tuple。
在python里,这段c代码相当于执行:
1. import math. --------------> pModule = PyImport_Import("math");
2. math.__dict__--------------> pDict = PyModule_GetDict(pModule);
3. math.__dict__["sqrt"]------> pFunc = PyDict_GetItemString(pDict, "sqrt");
4. math.__dict__["sqrt"](16)--->PyObject_CallObject(pFunc, 16)
找个是主要的流程,剩余的代码是错误检查和引用计数的处理。两个c的例子都可以在
python的文档里找到, 他们位于Embedding Python in Another Application
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
在python中嵌入c也不错,但我只在FreeBSD平台上实现了,win2k上需要VC6.0的支持,但我安装了VC6.0仍然不能完成编译.
总结是hack python还是到开源平台吧.
|
|
|
----
其实我很菜。
|
|
[Original]
[Print]
[Top]
|
|
|