Встраивание Python в C ++ - Запуск Python из программы C ++ - PullRequest
2 голосов
/ 28 ноября 2010

спасибо вам обоим за быстрый ответ :) Я думаю, я понял, что вы предлагаете, но это не совсем то, что мне нужно. Если честно, я не знаю, как правильно делать то, что мне нужно.

У меня есть программа, которой во время работы иногда требуется вызывать python, чтобы выполнить некоторые задачи. Мне нужна функция, которая вызывает Python и ловит питонов stdout

          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). Первым делом я попытался перенаправить sdtout и stderr в 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 ]

5 голосов
/ 28 ноября 2010

Пример кода, который вы используете, будет работать только тогда, когда ваш код Python возвращает объект, который может быть представлен типом C ++ int. Такое поведение вызвано этой строкой вашего кода:

int boostOutputStr = extract<int>(result);

Общая проблема, с которой вам приходится сталкиваться, заключается в том, что C ++ является строго типизированным языком, а Python - нет. Оператор python (или вызов функции python) может вернуть объект любого типа, и один вызов функции может вернуть объект другого типа, чем следующий вызов той же функции. В C ++ возвращаемый тип функции (а также типы аргументов) должны быть четко определены. Тем не менее, C ++ предоставляет шаблоны для случаев, когда вы хотите быть более гибкими. Определив одну шаблонную функцию (и хорошим примером является функция извлечения boost :: python), вы можете использовать эту функцию для конфигураций разных типов. Тем не менее, код функции вашего шаблона будет создан компилятором для каждого типа, с которым вы его используете. То есть метод шаблона избавляет вас от утомительной работы копирования и вставки, а затем изменения кода для всех типов, с которыми вы его используете. Компилятор делает это для вас. Но все типы должны быть четко определены во время компиляции. Вы не можете заставить функцию возвращать иногда int, а иногда string в зависимости от ввода пользователя. Вот для чего подходят языки сценариев, такие как Python или, возможно, другие языки высокого уровня. В C ++ все типы должны быть установлены во время компиляции кода.

Так что же делать в вашей ситуации?

Вы можете либо заставить pythonCallBackFunc вернуть result напрямую, не преобразовывая его в int. Таким образом, возвращаемое значение будет иметь тип 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);

Надеюсь, это поможет вам.

0 голосов
/ 29 мая 2012

вы можете просто разобрать строку и использовать PyRun_SimpleString.

0 голосов
/ 28 ноября 2010

Прежде всего, убедитесь, что вы прочитали и поняли ответ Свенора, если вы пытаетесь создать что-то более сложное, чем простой переводчик.Однако в этом конкретном случае вы можете заменить строку

    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 = true;} ')

...