【问题标题】:Embedding Python in C++ - Running Python from C++ program在 C++ 中嵌入 Python - 从 C++ 程序运行 Python
【发布时间】:2011-05-16 19:50:00
【问题描述】:

感谢你们两位的快速回复 :) 我想我理解你的建议,但这并不是我所需要的。老实说,我不知道什么是做我需要的正确技术。

我有一个程序,它在运行期间有时需要调用 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 的 sdtout 和 stderr 重定向到一个文件:

    #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'")

输出为空 ....

亚历克斯

【问题讨论】:

标签: c++ python embed


【解决方案1】:

您使用的示例代码仅在您的 Python 代码返回可以由 C++ 类型 int 表示的对象时才有效。此行为是由您的这行代码引起的:

int boostOutputStr = extract<int>(result);

您必须处理的一般问题是 C++ 是一种严格类型的语言,而 Python 不是。 python 语句(或 python 函数调用)可以返回任何类型的对象,并且对函数的一次调用可以返回与对同一函数的下一次调用不同类型的对象。在 C++ 中,必须明确定义函数的返回类型(以及参数的类型)。但是,C++ 为您希望更灵活的情况提供了模板。通过定义一个模板函数(boost::python 的提取函数就是一个很好的例子),您可以将该函数用于不同的类型配置。但是,您的模板函数代码将由编译器为您使用的每种类型实例化。 IE。模板方法只会让您免去复制粘贴的繁琐工作,然后为您使用的所有类型修改代码。编译器会为您做到这一点。但是所有类型都必须在编译时定义好。根据用户输入,您不能使函数有时返回 int 有时返回 string。这就是 Python 之类的脚本语言或其他高级语言的优势所在。在 C++ 中,必须在编译代码时设置所有类型。

那么在你的情况下该怎么办?

您可以让pythonCallBackFunc 直接返回result,而不将其转换为int。所以返回值的类型是object(来自 boost::python)并且代表一个 Python 对象。您可以使用 extract&lt;&gt; 将其转换为您稍后在代码中需要的任何类型。 (我假设您确实希望将 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);

希望对你有所帮助。

【讨论】:

  • 感谢您的回复,这不是我所需要的。我试图威慑地提出这个问题......
【解决方案2】:

首先,如果您尝试构建比普通解释器更复杂的东西,请确保您阅读并理解了 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()(例如程序/解释器启动)或用静态变量保护它(即 'static bool initialized = false; if (!initialized) { Py_Initialize(); initialized =真;}')

【讨论】:

  • 感谢您的回复,我已经更新了问题。我一直在寻找这样的东西,但它并不能解决所有问题。例如,当我提供以下命令时,它不起作用:pythonCallBackFunc("print 'a'+'b'") it through an exception incited of printing ab
【解决方案3】:

您可以只解析字符串并使用 PyRun_SimpleString。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-16
    • 1970-01-01
    相关资源
    最近更新 更多