2008-10-18 4 views
11

C++ 프로젝트에서 작업하면서 제 핵심 비즈니스가 아닌 제 3 자 라이브러리를 찾고있었습니다. 필자는 실제로 필요한 라이브러리를 찾았지만 Python으로 작성되었습니다. Boost.Python 라이브러리를 사용하여 C++에 파이썬 코드를 삽입하는 실험을하기로 결정했습니다. 'Func라고'CPP에 임베드 된 Python : CPP로 데이터를 다시 가져 오는 방법

import thirdparty 

def MyFunc(some_arg): 
    result = thirdparty.go() 
    print result 

이제 문제는 이것이다 :이처럼 보이는 파이썬 코드의

#include <string> 
#include <iostream> 
#include <boost/python.hpp> 

using namespace boost::python; 

int main(int, char **) 
{ 
    Py_Initialize(); 

    try 
    { 
     object module((handle<>(borrowed(PyImport_AddModule("__main__"))))); 

     object name_space = module.attr("__dict__"); 
     object ignored = exec("from myModule import MyFunc\n" 
          "MyFunc(\"some_arg\")\n", 
          name_space); 

     std::string res = extract<std::string>(name_space["result"]); 
    } 
    catch (error_already_set) 
    { 
     PyErr_Print(); 
    } 

    Py_Finalize(); 
    return 0; 
} 

A (매우) 단순화 된 버전 :

는 C++ 코드는 다음과 같이 보입니다 잘 실행됩니다, 나는 '결과'의 프린트를 볼 수 있습니다. 내가 할 수없는 것은 C++ 코드에서 '결과'를 다시 읽는 것입니다. 추출 명령은 어떤 네임 스페이스에서도 '결과'를 찾지 않습니다. '결과'를 전역으로 정의하려고 시도했지만 튜플을 반환하려고 시도했지만 작업을 수행 할 수 없습니다.

답변

6

먼저 함수를 return 값으로 변경하십시오. print 인 경우 가치를 되찾고 싶어하기 때문에 상황이 복잡해집니다. 이처럼 MyModule.py 외모를 가정 :

이제
import thirdparty 

def MyFunc(some_arg): 
    result = thirdparty.go() 
    return result 

, 당신이 원하는 것을 할, 당신은 documentation says로, 기본 삽입 넘어 가야한다. 여기에 귀하의 기능을 실행하는 전체 코드는 다음과 같습니다

내가 마침내 boost.python 사용하여 일을 가지고 ΤΖΩΤΖΙΟΥ, 조쉬와 Nosklo의 응답에 따라
#include <Python.h> 

int 
main(int argc, char *argv[]) 
{ 
    PyObject *pName, *pModule, *pFunc; 
    PyObject *pArgs, *pArg, *pResult; 
    int i; 

    Py_Initialize(); 
    pName = PyString_FromString("MyModule.py"); 
    /* Error checking of pName left out as exercise */ 

    pModule = PyImport_Import(pName); 
    Py_DECREF(pName); 

    if (pModule != NULL) { 
     pFunc = PyObject_GetAttrString(pModule, "MyFunc"); 
     /* pFunc is a new reference */ 

     if (pFunc) { 
      pArgs = PyTuple_New(0); 
      pArg = PyString_FromString("some parameter") 
      /* pArg reference stolen here: */ 
      PyTuple_SetItem(pArgs, 0, pArg); 
      pResult = PyObject_CallObject(pFunc, pArgs); 
      Py_DECREF(pArgs); 
      if (pResult != NULL) { 
       printf("Result of call: %s\n", PyString_AsString(pResult)); 
       Py_DECREF(pResult); 
      } 
      else { 
       Py_DECREF(pFunc); 
       Py_DECREF(pModule); 
       PyErr_Print(); 
       fprintf(stderr,"Call failed\n"); 
       return 1; 
      } 
     } 
     else { 
      if (PyErr_Occurred()) 
       PyErr_Print(); 
      fprintf(stderr, "Cannot find function"); 
     } 
     Py_XDECREF(pFunc); 
     Py_DECREF(pModule); 
    } 
    else { 
     PyErr_Print(); 
     fprintf(stderr, "Failed to load module"); 
     return 1; 
    } 
    Py_Finalize(); 
    return 0; 
} 
+1

훨씬 더 포괄적 인 답을 항목 할당을 지원하지 않습니다 'NoneType'개체 : nosklo를, I PyRun_String 예제를 사용하여 대답을 확장하는 것이 좋습니다. 더 많은 유연성을 허용합니다. – tzot

+0

당신의'pArgs = PyTuple_New (0);'은 0이 아닌 1을 전달해야한다고 생각합니다. –

0

MyFunc에서 결과를 반환 할 수 있어야합니다. MyFunc의 결과는 현재 "무시 된"변수에 저장됩니다. 이렇게하면 다른 방법으로 액세스 할 필요가 없습니다.

+0

상관없이 Func라고에서 반환되는 것을, 내가 얻을 : 형식 오류를 (내 생각)에서, 동료 부모 나보다 –

1

필자가 원하는 것은 PyObject로 호출하는 함수의 반환 값을 반환하는 PyObject_CallObject(<py function>, <args>)이거나 단일 표현식을 평가하고 결과를 반환하는 PyRun_String(<expression>, Py_eval_input, <globals>, <locals>)입니다.

3

:

파이썬 :

import thirdparty 

def MyFunc(some_arg): 
    result = thirdparty.go() 
    return result 

C++를 :

#include <string> 
#include <iostream> 
#include <boost/python.hpp> 

using namespace boost::python; 

int main(int, char **) 
{ 
    Py_Initialize(); 

    try 
    { 
     object module = import("__main__"); 
     object name_space = module.attr("__dict__"); 
     exec_file("MyModule.py", name_space, name_space); 

     object MyFunc = name_space["MyFunc"]; 
     object result = MyFunc("some_args"); 

     // result is a dictionary 
     std::string val = extract<std::string>(result["val"]); 
    } 
    catch (error_already_set) 
    { 
     PyErr_Print(); 
    } 

    Py_Finalize(); 
    return 0; 
} 

몇 가지 중요한 점 :

,536,
  1. 'exec'을 편의 'exec_file'으로 변경했으며 일반 'exec'와도 작동합니다. 이 이제 두 번 NAME_SPACE를 전달하여 고정 - 그것은 실패
  2. 주된 이유는 내가 '간부'또는 'exec_file'에 "로컬"name_sapce를 통과하지 못한 것입니다.
  3. 파이썬 함수가 유니 코드 문자열을 반환하는 경우
  4. , 그들은하지 컨버터블 '표준 : : 문자열'에, 그래서 는 '함수 .encode ('ASCII ','무시 ')'모든 파이썬 문자열을 접미사했다.