在C++中嵌入Python - 从C++程序运行Python
谢谢你们俩快速的回复 :)
我觉得我明白你们的建议了,但这并不是我真正需要的。老实说,我不知道该用什么正确的方法来实现我想要的功能。
我有一个程序,在运行过程中,有时需要调用Python来执行一些任务。我需要一个函数,可以调用Python并捕获Python的输出。
pythonCallBackFunc(const char* pythonInput)
这个函数就是用来实现这个功能的。
举个例子:
pythonCallBackFunc("5**2") needs to print on stdin(or some other file):
PythonResult: 25
pythonCallBackFunc("print 5**2") needs to print on stdin(or some other file):
PythonResult: 25
pythonCallBackFunc("'a'+'b'") needs to print on stdin(or some other file):
PythonResult: 'ab'
pythonCallBackFunc("print 'a'+'b'") needs to print on stdin(or some other file):
PythonResult: ab
pythonCallBackFunc("execfile('temp.py')")
it should print nothing but is needs to run the temp.py script
the next 2 calls need to print the value of result, meaning 4.
pythonCallBackFunc("result = 4")
pythonCallBackFunc("print result")
我遇到的问题是要捕获给定命令的所有Python输出(pythonInput)。我尝试的第一件事是使用这个脚本将Python的标准输出和错误输出重定向到一个文件:
#stdout.py
import sys
saveout = sys.stdout
fsock = open('out.log', 'w')
sys.stdout = fsock
#stdout_close.py
sys.stdout = saveout
fsock.close()
#stdout_close.py
fsock = open('error.log', 'w')
sys.stderr = fsock
重定向之后,我使用了函数Py_run_SimpleString。
这还不错,但这个函数忽略了这些类型的命令:
Py_run_SimpleString("'a'+'b'")
结果是空的……
Alex
3 个回答
你可以直接解析字符串,然后使用 PyRun_SimpleString。
你现在用的示例代码只会在你的Python代码返回一个可以用C++的
int boostOutputStr = extract<int>(result);
你需要面对的一个主要问题是,C++是一种严格类型的语言,而Python则不是。Python中的一条语句(或者一个函数调用)可以返回任何类型的对象,而且同一个函数的不同调用可以返回不同类型的对象。在C++中,函数的返回类型(以及参数的类型)必须是明确的。不过,C++提供了模板功能,可以让你在某些情况下更加灵活。通过定义一个模板函数(比如boost::python中的extract函数就是一个很好的例子),你可以用这个函数处理不同类型的配置。但是,编译器会为你使用的每一种类型实例化这个模板函数。也就是说,模板方法只是帮你省去了复制粘贴和修改代码的繁琐工作。编译器会为你完成这些工作。但所有类型必须在编译时就明确好。你不能让一个函数根据用户输入有时返回
那么在你的情况下该怎么办呢?
你可以让pythonCallBackFunc
直接返回result
,而不进行任何类型转换,这样返回值就是一个类型为object
(来自boost::python)的对象,表示一个Python对象。你可以在后面的代码中用extract<>
将其转换为你需要的任何类型。(我假设你确实想把Python表达式的返回值传回你的代码,而不是一直通过cout
打印出来。)
或者,你也可以把你的函数pythonCallBackFunc
做成一个模板函数。
template<class ReturnType>
void pythonCallBackFunc(string inputStr){
Py_Initialize();
try
{
str boostInputStr(inputStr.c_str());
object result = eval(boostInputStr);
return extract<ReturnType>(result);
//Py_Finalize() #not calling because of the boost.python
}
catch(error_already_set const &)
{
//do somthing
}
}
...在这种情况下,你需要用合适的类型来调用它,比如:
pythonCallBackFunc<int>(inputStr);
希望这些对你有帮助。
首先,如果你想构建比简单的解释器更复杂的东西,确保你先阅读并理解svenor的回答。不过在这个特定的情况下,你可以把这一行
int boostOutputStr = extract<int>(result);
替换成
std::string boostOutputStr = extract<std::string>(str(result));
这样就能得到你想要的结果。这里的str(result)部分是把你在Python中计算出来的结果转换成字符串形式,这样如果你只是想把它输出到std::cout,这样做就足够了。
如果你决定使用带模板的pythonCallBackFunc(),有两点需要注意:
(1) 声明时返回类型应该是'ReturnType'而不是'void'
(2) 你应该在其他地方调用Py_Initialize()(比如程序或解释器启动时),或者用一个静态变量来保护它(也就是'静态 bool initialized = false; 如果 (!initialized) { Py_Initialize(); initialized = true; }')。