开发者

Embedding Python in C++ - Running Python from C++ program

thank you both for a quick response :) i think i understood what you suggest but it is not exactly what i need. To be honest i don't know what is the right technique to do what i need.

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

          pythonCallBackFunc(const char* pythonInput)

This function is the function to do that.

for example:

     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.
     pythonCallBac开发者_StackOverflow社区kFunc("result = 4")
     pythonCallBackFunc("print result")

My problem is to catch all the python output for a given command (pythonInput). First thing I've tried is to redirect python's sdtout and stderr to a file using this script:

    #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  

and after the redirection, I've used the function Py_run_SimpleString

it was ok but this function ignored this types of commands:

    Py_run_SimpleString("'a'+'b'")

the output was empty ....

Alex


The example code you are using will only work when your Python code returns an object that can be represented by the C++ type int. This behaviour is caused by this line of your code:

int boostOutputStr = extract<int>(result);

The general problem you have to deal with is that C++ is a strictly typed language, whereas Python is not. A python statement (or a python function call) can return any type of object, and one call to a function can return a different type of object than the next call to the same function. In C++, the return type of a function (and also the types of arguments) must be well defined. However, C++ provides templates for cases where you want to be more flexible. By defining one template function (and the extract function of boost::python is a good example) you can use that function for different type configurations. However, your template function code will be instantiated by the compiler for each and every type you use it with. I.e. the template method only spares you the tedious work of copy-and-pasting and then modifying your code for all types you use it with. The compiler does that for you know. But all types must be well defined at compile time. You cannot make a function return sometimes int and sometimes string depending on the user input. That is what scripting languages like Python, or maybe other high level languages, are good for. In C++, all types must be set at the time your code is compiled.

So what to do in your situation?

You could either make pythonCallBackFunc return the result directly, without converting it to int at all. So the return value would be of type object (from boost::python) and would represent a Python object. You could convert that with extract<> to whatever type you need later in your code. (I am assuming that you want indeed the return value of your Python expression passed back to your code, not printed out through cout all the time.)

Or, you could make your function pythonCallBackFunc a templated function as well.

    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
          }
     }

...in which case you'd have to call it with the appropriate type, as for example

       pythonCallBackFunc<int>(inputStr);

Hope this is of help for you.


First of all, make sure you read and understand svenor's answer if you're trying to build anything more complicated than a trivial interpreter. However, in this particular case you can replace the line

    int boostOutputStr = extract<int>(result);

with

    std::string boostOutputStr = extract<std::string>(str(result));

and get what you're looking for. The str(result) part converts whatever type your Python expression evaluated as into its string representation, which is adequate if all you need to do is write it to std::cout.

Two things to note if you decide to go with the templated pythonCallBackFunc():

(1) The declaration should have return type 'ReturnType' rather than 'void'

(2) You should either call Py_Initialize() somewhere else (e.g. program/interpreter startup) or protect it with a static variable (i.e. 'static bool initialized = false; if (!initialized) { Py_Initialize(); initialized = true; }')


you can just parse string and use PyRun_SimpleString.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜