如何在 c++ 中捕获 python stdout代码
我有一个程序,在运行过程中有时需要调用 python 来执行一些任务。我需要一个调用 python 并捕获 python 标准输出并将其放入某个文件中的函数。 这是函数的声明
pythonCallBackFunc(const char* pythonInput)
我的问题是捕获给定命令的所有 python 输出(pythonInput)。 我没有 python API 的经验,我不知道什么是正确的技术来做到这一点。 我尝试的第一件事是使用 Py_run_SimpleString 重定向 python 的 sdtout 和 stderr 这是我编写的代码的一些示例。
#include "boost\python.hpp"
#include <iostream>
void pythonCallBackFunc(const char* inputStr){
PyRun_SimpleString(inputStr);
}
int main () {
...
//S0me outside functions does this
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("old_stdout = sys.stdout");
PyRun_SimpleString("fsock = open('python_out.log','a')");
PyRun_SimpleString("sys.stdout = fsock");
...
//my func
pythonCallBackFunc("print 'HAHAHAHAHA'");
pythonCallBackFunc("result = 5");
pythonCallBackFunc("print result");
pythonCallBackFunc("result = 'Hello '+'World!'");
pythonCallBackFunc("print result");
pythonCallBackFunc("'KUKU '+'KAKA'");
pythonCallBackFunc("5**3");
pythonCallBackFunc("prinhghult");
pythonCallBackFunc("execfile('stdout_close.py')");
...
//Again anothers function code
PyRun_SimpleString("sys.stdout = old_stdout");
PyRun_SimpleString("fsock.close()");
Py_Finalize();
return 0;
}
有更好的方法吗?此外,由于某种原因,PyRun_SimpleString在获取某些数学表达式时不执行任何操作,例如 PyRun_SimpleString("5**3") 不打印任何内容(python conlsul 打印结果:125)
也许这很重要,我正在使用 Visual Studio 2008。 谢谢, Alex
根据 Mark 的建议进行了更改:
#include <python.h>
#include <string>
using namespace std;
void PythonPrinting(string inputStr){
string stdOutErr =
"import sys\n\
class CatchOut:\n\
def __init__(self):\n\
self.value = ''\n\
def write(self, txt):\n\
self.value += txt\n\
catchOut = CatchOut()\n\
sys.stdout = catchOut\n\
sys.stderr = catchOut\n\
"; //this is python code to redirect stdouts/stderr
PyObject *pModule = PyImport_AddModule("__main__"); //create main module
PyRun_SimpleString(stdOutErr.c_str()); //invoke code to redirect
PyRun_SimpleString(inputStr.c_str());
PyObject *catcher = PyObject_GetAttrString(pModule,"catchOut");
PyObject *output = PyObject_GetAttrString(catcher,"value");
printf("Here's the output: %s\n", PyString_AsString(output));
}
int main(int argc, char** argv){
Py_Initialize();
PythonPrinting("print 123");
PythonPrinting("1+5");
PythonPrinting("result = 2");
PythonPrinting("print result");
Py_Finalize();
return 0;
}
运行 main 后得到的输出:
Here's the output: 123
Here's the output:
Here's the output:
Here's the output: 2
这对我来说有好处,但只有一个问题,应该是
Here's the output: 123
Here's the output: 6
Here's the output:
Here's the output: 2
我不知道为什么,但运行此命令后:PythonPrinting("1+5") , PyString_AsString(output) 命令返回一个空字符串 (char*) 而不是 6...:( 我可以做些什么来不丢失此输出?
谢谢, 亚历克斯
I have a program which during it's run sometimes needs to call python in order to preform some tasks. I need a function that calls python and catches pythons stdout and puts it in some file.
This is a declaration of the function
pythonCallBackFunc(const char* pythonInput)
My problem is to catch all the python output for a given command (pythonInput).
I have no experience with python API and I don't know what is the right technique to do this.
First thing I've tried is to redirect python's sdtout and stderr using Py_run_SimpleString
this is some example of the code i've written.
#include "boost\python.hpp"
#include <iostream>
void pythonCallBackFunc(const char* inputStr){
PyRun_SimpleString(inputStr);
}
int main () {
...
//S0me outside functions does this
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("old_stdout = sys.stdout");
PyRun_SimpleString("fsock = open('python_out.log','a')");
PyRun_SimpleString("sys.stdout = fsock");
...
//my func
pythonCallBackFunc("print 'HAHAHAHAHA'");
pythonCallBackFunc("result = 5");
pythonCallBackFunc("print result");
pythonCallBackFunc("result = 'Hello '+'World!'");
pythonCallBackFunc("print result");
pythonCallBackFunc("'KUKU '+'KAKA'");
pythonCallBackFunc("5**3");
pythonCallBackFunc("prinhghult");
pythonCallBackFunc("execfile('stdout_close.py')");
...
//Again anothers function code
PyRun_SimpleString("sys.stdout = old_stdout");
PyRun_SimpleString("fsock.close()");
Py_Finalize();
return 0;
}
Is there a better way to do this? Besides, for some reason PyRun_SimpleString does nothing when it gets some mathematical expression, for example PyRun_SimpleString("5**3") prints nothing (python conlsul prints the result: 125)
maybe it is important, i am using visual studio 2008.
Thanks,
Alex
Changes I've made according Mark's suggestion:
#include <python.h>
#include <string>
using namespace std;
void PythonPrinting(string inputStr){
string stdOutErr =
"import sys\n\
class CatchOut:\n\
def __init__(self):\n\
self.value = ''\n\
def write(self, txt):\n\
self.value += txt\n\
catchOut = CatchOut()\n\
sys.stdout = catchOut\n\
sys.stderr = catchOut\n\
"; //this is python code to redirect stdouts/stderr
PyObject *pModule = PyImport_AddModule("__main__"); //create main module
PyRun_SimpleString(stdOutErr.c_str()); //invoke code to redirect
PyRun_SimpleString(inputStr.c_str());
PyObject *catcher = PyObject_GetAttrString(pModule,"catchOut");
PyObject *output = PyObject_GetAttrString(catcher,"value");
printf("Here's the output: %s\n", PyString_AsString(output));
}
int main(int argc, char** argv){
Py_Initialize();
PythonPrinting("print 123");
PythonPrinting("1+5");
PythonPrinting("result = 2");
PythonPrinting("print result");
Py_Finalize();
return 0;
}
The output i get after running main:
Here's the output: 123
Here's the output:
Here's the output:
Here's the output: 2
It is good for me , but only one problem, it should be
Here's the output: 123
Here's the output: 6
Here's the output:
Here's the output: 2
I dont know why but after running this command: PythonPrinting("1+5"), PyString_AsString(output) command returns an empty string (char*) instead of 6... :( Is there somthing i can do not to loose this output?
Thaks,
Alex
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是我最近开发的一个 C++ 友好的解决方案。
我在我的博客上解释了它的一些细节: C++ 中的 Python sys.stdout 重定向,我还指向 GitHub 上的存储库,可以在其中找到最新版本。
这是基于发布此答案时的当前代码的完整示例:
这允许使用任何类型的可调用 C++ 实体拦截 sys.stdout.write 输出:自由函数、类成员函数、命名函数函数对象甚至匿名函数,如上面的示例所示,我使用 C++11 lambda。
请注意,这是展示基本概念的最小示例。在生产就绪的代码中,当然需要更多关注
PyObject
的引用计数、摆脱全局状态等。Here is a C++ friendly solution I have developed lately.
I explain a few details of it on my blog: Python sys.stdout redirection in C++ where I also point to repository at my GitHub where most recent version can be found.
Here is complete example based on the current code at the time of posting this answer:
This allows to intercept
sys.stdout.write
output with any kind of callable C++ entity: free function, class member function, named function objects or even anonymous functions as in the example above where I use C++11 lambda.Note, this is a minimal example to present the essential concept. In production-ready code, it certainly needs more attention around reference counting of
PyObject
, getting rid of global state, and so on.如果我正确地阅读你的问题,你想将 stdout/stderr 捕获到 C++ 中的变量中吗?您可以通过将 stdout/stderr 重定向到 python 变量,然后在 C++ 中查询该变量来完成此操作。请注意,我没有进行以下正确的引用计数:
If I'm reading your question correctly, you want to capture stdout/stderr into a variable within your C++? You can do this by redirecting stdout/stderr into a python variable and then querying this variable into your C++. Please not that I have not done the proper ref counting below:
我知道这个问题很老了,但问题的一部分尚未得到解答:
以下是步骤(适用于 Python 3.4):
使用 Mark 的解决方案将 stdout/stderr 重定向到 Python 变量:https://stackoverflow .com/a/4307737/1046299
从Python源代码复制函数
PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
。它位于文件pythonrun.c
中,
修改
PyRun_InteractiveOneObject
函数名称和签名,以便新函数采用const char*
(您的命令)作为第一个参数而不是 FILE* 。然后,您需要在函数实现中使用PyParser_ASTFromStringObject
而不是PyParser_ASTFromFileObject
。请注意,您需要从 Python 中按原样复制函数run_mod
,因为它是在函数内调用的。使用您的命令调用新函数,例如
1+1
。 Stdout 现在应该接收输出2
。I know this question is old, but one part of the question has not been answered yet:
Here are the steps (for Python 3.4):
Redirect stdout/stderr into a Python variable using Mark's solution: https://stackoverflow.com/a/4307737/1046299
Copy function
PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
from Python source code. It is located in filepythonrun.c
Modify the
PyRun_InteractiveOneObject
function name and signature so that the new function takes aconst char*
(your command) as first parameter instead of aFILE*
. Then you will need to usePyParser_ASTFromStringObject
instead ofPyParser_ASTFromFileObject
in the function implementation. Note that you will need to copy the functionrun_mod
as is from Python since it is called within the function.Call the new function with your command, for example
1+1
. Stdout should now receive the output2
.