====== Embedded Python ======
===== 개괄 =====
파이썬이 다른 언어와 어떻게 잘 어울릴 수 있는지 증명하는 과정?
파이썬으로도 좋은 GUI를 만들 수 있겠지만, 시스템쪽으로 Qt library를 사용하기로 결정하였고, 이것으로 사용하면 더욱 좋은 그래픽 인터페이스를 만들 수 있겠다는 생각을 하였다. 그러나 네트워크 및 인증 모듈 등을 도입하는 과정에서 기존의 C/C++도 나쁘지는 않지만, 파이썬의 기능이 워낙 막강하고 편리하기 때문에 일단 파이썬을 핵심 모듈로 사용하고, 그 이외의 모듈은 Qt를 사용하는 방법을 채택하였다.
이 방법이 아름다운 이유는, 핵심 라이브러리는 여러 시스템, MacOS, Windows, Linux 등에 포팅된다. C/C++로 GUI를 일단 생성하기로 마음먹었지만, 차후 C# 내지는 다른 언어로도 작성될 수 있다고 생각한다. 그런데 이 핵심 모듈을 여러 언어로 작성하기보다, 파이썬으로만 고수한다면 어떨까? 핵심 모듈과 다른 모듈과의 인터페이스만 잘 맞추어주면 되는 것 아닐까.
파이썬 자체의 생산성이 워낙 높기 때문에 핵심 모듈이 점차 다른 언어로 뒷받침된다 하더라도 일단은 파이썬으로도 충분히 커버 가능할 것이다. 이런 이유로 embedded python을 계속 생각하게 되었다.
파이썬을 타 언어와 접목하는 방법에는 두 가지 요령이 있다. 다른 언어가 파이썬의 모듈을 실행하는 것, 반대로 파이썬에서 타 언어의 모듈을 실행하는 방법이다. 전자가 현재 문서에서 말하는 '내장된 파이썬(embedded python)'이고, 후자는 파이썬이 다른 언어로 '확장'되므로 '확장된 파이썬(extended python)'이라 칭한다.
이 문서에서는 내장된 파이썬에 주목하고 이것을 사용하기 위해 어떻게 해야 하는지에 대해 실질적으로 접근해 보도록 한다.
전반적인 사항에 대해서는 생략하고, 주로 파이썬에서 제공하는 C 라이브러리를 직접 사용하는 법과, boost library를 이용하여 보다 편리하게 사용하는 법에 대해 논하도록 하자.
물론 파이썬은 C/C++ 뿐 아니라 C#, Java 등과도 어울릴 수 있으나 문서를 참고하면 일단 C API에 대해서만 서술하고 있다.
일단 C API를 직접 활용하는 방법과, 그리고 boost::python 사용하여 보다 쉽게 코드를 작성하는 방법에 대해 기록하고자 한다.
설명하려는 사람이 가진 마법의 단어가 있다. "매뉴얼을 보세요."
물론 나도 모든 것을 설명할 수 없기에 결국에는 이 마법의 단어를 사용할 수 밖에는 없겠지만, 최소한 매뉴얼을 보고 언제 어디서든 방법을 따라할 만큼의 디테일한 설명, 다시 말해 매뉴얼이 다 하지 못한 이야기 정도는 할 것이다.
이 문서가 설명하고자 하는 embedded python의 목표는 다음과 같다.
- 파이썬으로 작성한 모듈의 변수, 함수, 클래스를 외부 프로그램이 임의로 생성할 수 있도록 한다.
- 생성된 객체에 값을 입력하고, 접근하며, 출력을 받아올 수 있도록 한다.
===== C 라이브러리를 직접 활용하기 ======
==== C 프로그램에서 파이썬 부리기: Hello, World ====
다음과 같은 코드를 작성합니다. 무지하게 간단하지만, 천천히 시작하도록 하지요.
#include
int main(int argc, char** argv)
{
Py_SetProgramName(argv[0]);
Py_Initialize();
PyRun_SimpleString("print \'Hello, World!\'\n");
Py_Finalize();
return 0;
}
==== 유닉스 상에서 컴파일하기 ====
[[http://docs.python.org/2/extending/embedding.html#compiling-and-linking-under-unix-like-systems|문서]]를 참고하면 이렇게 작성한 코드는 컴파일을 해야 합니다. 하지만 라이브러리 링크 정보와 헤더 정보를 주지 않으면 에러가 나게 되겠죠. 문서는 이 라이브러리 링크 정보와 헤더 정보를 쉽게 알아내는 법에 대해 설명합니다.
파이썬 버전이 2.7인 경우,
*''python2.7-config --cflags'': 헤더 정보 및 컴파일 정보를 출력합니다.
*''python2.7-config --ldflags'': 링크 정보를 출력합니다.
그러므로 이 정보를 이용하면 다음과 같이 위 코드를 컴파일 할 수 있습니다.
gcc `python2.7-config --cflags` `python2.7-config --ldflags` -o hello_py hello_py.c
그런데 이렇게 매번 컴파일하기 힘드니, Makefile을 따로 만들어 두겠습니다.
CC = /usr/bin/gcc
CONFIG = /opt/local/bin/python2.7-config
CFLAGS = `$(CONFIG) --cflags`
LDFLAGS = `$(CONFIG) --ldflags`
TAR = hello_py.out # 여기에 .out 파일을 추가하세요
OBJ = $(TAR:.out=.o)
SRC = $(TAR:.out=.c)
all: $(TAR)
.o.out: $(OBJ)
$(CC) $(LDFLAGS) -o $@ $<
.c.o: %.c
$(CC) $(CFLAGS) -c $<
clean:
rm -fr $(TAR) $(OBJ)
''TAR = hello_py.out'' 이 적힌 줄에 공백으로 계속 실행 파일의 이름을 입력하면 그에 맞게 소스가 컴파일됩니다.
이렇게 만들어진 바이너리 파일을 실행하면 다음과 같은 결과가 나올 것입니다.
Hello, World!
==== 첫번째 실행 결과에 대해 ====
결과는 성공적이지만, 왠지 석연치 않습니다. ''PyRun_SimpleString()'' 함수는 이름 그대로 너무 간단합니다. 우리의 목표에는 미치지 못하는 결과입니다.
==== 두번째 코드: 함수 호출 ====
두번째는 파이썬의 함수를 호출해 볼 것입니다. 치사하게 인자가 없는 함수를 부르진 않을게요.
이것도 문서에 있는 예제로, 다음과 같은 역할을 하도록 프로그램되어 있습니다.
def multiply(a,b):
print "Will compute", a, "times", b
c = 0
for i in range(0, a):
c = c + b
return c
우리는 이 파이썬 함수를 C 코드에서 부를 것입니다. 그러나 이전처럼 뭔가 소스 코드가 하드코딩 되어 있다든지 하는 법 없이 동작하게 할 것입니다. 문서에서는 긴 소스를 죽 나열해두고 나중에 설명을 한 반면, 여기서는 어떻게 프로그램이 흘러가는지에 대해 중점을 맞추고 서술하겟습니다. 그 편이 더 이해하기 좋습니다.
=== Py_SetProgramName() ===
Py_Initialize() 함수가 호출되기 전에 호출해야 하는 함수입니다. 파이썬이 실행 중 가지게 되는 자신의 이름입니다. 그러니까 이 함수로 전달된 값은 파이썬의 ''sys.argv[0]''와 동일한 것입니다. 이 함수는 선택적이어서 굳이 호출하지 않아도 됩니다. 이 경우 이름은 'python'이 된다고 합니다.
=== Py_Initialize(), Py_Finalize() ===
파이썬 API 사용 전후에 **반드시** 불려야 하는 함수입니다.
=== 파이썬 코드로부터 어떤 일들이 일어나는지 먼저 유추해보기 ===
우선 multiply.py를 부르는 파이썬 스크립트와, 그것을 실행했을 때 일어나는 과정에 대해 간단히 생각해보죠. 이걸 우선 유념해두고 코드를 읽는 편이 낫다고 생각합니다.
그럼 간단하게 multiply.py를 사용하는 파이썬 스크립트를 생각해 보죠.
import multiply
if __name__ == '__main__':
print multiply.multiply(4, 5)
이 코드는 다음과 같이 동작합니다.
- multiply 모듈(multply.py 파일)을 로드합니다.
- 그러면 파이썬은 자신이 알고 있는 경로에서 multiply.py라는 파일을 찾아서 import를 시도합니다.
- 파일을 찾으면 성공적으로 모듈을 로딩할 것이고, 아니면 에러를 낼 것입니다.
- if 블록을 수행합니다. 파이썬은 명시적인 main() 함수가 없으므로 보통 이렇게 그 스크립트를 실행합니다. multiply 모듈의 함수 multiply를 호출합니다. 두 개의 정수 인자 4와 5도 같이 함수에 넘깁니다.
- 함수는 정의된 동작을 수행하고 정수를 하나 넘깁니다. 그리고 그것을 print문을 이용하여 출력합니다.
- 에러가 없다면 정상적으로 종료될 것입니다.
==== C 코드에서 파이썬 함수 호출 ====
상당히 간단한 함수 호출이지만, 상당히 번거로운 작업들이 많습니다. 이 번거로운 작업들의 패턴은 크게 이렇게 생각할 수 있습니다.
* C의 데이터를 파이썬의 객체형으로 표현하는 일
* C에서 파이썬의 모듈과 객체를 찾아 그것을 참조하는 일
* 참조된 객체를 호출하는 일
* 객체가 반환한 결과를 파이썬으로부터 C로 표현하는 일
* 기타 여러 제어를 위한 일
=== C의 데이터를 파이썬의 객체형으로 표현 ===
우선 C의 데이터를 파이썬의 객체형으로 표현하는 법에 대해 설명합니다. C에서 파이썬의 문자열을 생성하는 함수는 [[http://docs.python.org/2/c-api/string.html#PyString_FromString|PyString_FromString()]]입니다. 리턴 형은 ''PyObject*''인데 모든 파이썬의 데이터는 이 ''PyObject''입니다. 파이썬의 어떤 자료형이라도 ''PyObject''로 표현되므로, 항상 주의하여야 합니다.
char *str = NULL;
PyObject* pString;
str = ...;
pString = PyString_FromString(str);
위 코드에서 ''PyString_FromString()''의 반환을 참조하는 ''pString''과 다른 API를 활용하여 마치 파이썬에서 문자열 함수를 사용하는 것과 유사하게 사용할 수 있습니다. 그러나 모든 기능이 제공되는 것은 아닙니다. 문서의 [[http://docs.python.org/2/c-api/concrete.html|Concrete Objects Layer]]를 참고하면 더 많은 자료형에 대해 객체 생성을 할 수 있습니다.
=== 파이썬 모듈을 찾아 import 하기 ===
[[http://docs.python.org/2/c-api/import.html|Importing Modules]]의 문서를 참고합니다.
한 예는 [[http://docs.python.org/2/c-api/import.html#PyImport_Import|PyImport_Import()]]입니다. 모듈 이름을 넘기면 모튤을 로딩합니다. 반환값은 그 모듈을 참조합니다. 이 때 모듈 이름은 C의 문자열이 아니라, 파이썬의 문자열입니다.
PyObject *pModuleName;
PyObject *pSysModule;
pModuleName = PyString_FromString("sys");
pSysModule = PyImport_Import(pModuleName);
=== 파이썬의 변수/함수/클래스를 참조하고 호출하기 ===
파이썬의 변수, 함수, 클래스는 모두 모듈의 '속성(attribute)'입니다. 그러므로 해당 모듈에서 변수, 함수, 클래스 등을 참조하려면, '[[http://docs.python.org/2/c-api/object.html#object-protocol|Object Protocol]]' 섹션의 [[http://docs.python.org/2/c-api/object.html#PyObject_GetAttrString|PyObject_GetAttrString()]]함수를 이용합니다. 이 외에도 여러 함수가 있으므로 문서를 한 번 꼼꼼하게 읽어 둘 필요가 있습니다.
PyObject *pVersion;
PyObject *pFunction;
PyObject *pReturn;
pVersion = PyObject_GetAttrString(pSysModule, "version");
pFunction = PyObject_GetAttrString(pSysModule, "getfilesystemencoding");
pReturn = PyObject_CallObject(pFunction, NULL);
class sampleClass:
def __init__(self, arg1, arg2, arg3):
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
...
위와 같은 파이썬 클래스가 정의되어 있습니다. 이것을 인스턴스화 하는 법은 아래와 같습니다.
PyObject *pSampleClass;
PyObject *pInstance;
PyObject *pArgList;
pSampleClass = PyObject_GetAttrString(pSampleClass, "SampleClass");
pArgList = Py_BuildValue("sid", arg1, arg2, arg3); /* string, integer, double */
pInstance = PyObject_CallObject(pSampleClass, pArgList);
[[http://docs.python.org/2/c-api/object.html#PyObject_CallObject|PyObject_CallObject()]]는 호출할 수 있는 (callable) 오브젝트를 호출하고, 값을 반환받습니다. ''getfilesystemencoding''는 호출 가능하므로 pReturn에 값이 반환될 것입니다. 반환된 값을 C에서 어떻게 끄집어 내야 할지는 좀 더 후에 서술하겠습니다.
=== 반환된 값을 C로 끄집어내기 ===
''PyObject''의 데이터를 C로 가져오는 함수는 Py**[XXX]**_As**[YYY]** 스타일로 정의되어 있습니다. 그래서 오브젝트가 실수형인 경우 실수에서 double 타입으로 가져올 때는 [[http://docs.python.org/2/c-api/float.html#PyFloat_AsDouble|PyFloat_AsDouble()]]을 사용하고, 정수형인 경우 [[http://docs.python.org/2/c-api/int.html#PyInt_AsLong|PyInt_AsLong()]]을 사용하는 형태를 취하고 있습니다.
int intReturn;
float floatReturn;
Py_complex complexReturn;
pIntReturn = PyInt_AsLong(pyIntObject);
pFloatReturn = (float)PyFloat_AsDouble(pyFloatObject);
pComplexReturn = PyComplex_AsCComplex(pyComplexObject);
리스트나 딕셔너리에서 값을 가져올 때는 ''PyList_Size(), PyList_GetItem(), PyList_SetItem(), PyDict_Size(), PyDict_GetItem(), PyDict_SetItem()''을 사용합니다. 사용은 매우 직관적입니다.
=== 레퍼런스 카운팅 ===
파이썬에서는 메모리 관리를 할 필요가 없습니다. 내부적으로 메모리 관리를 해 주지요. 그러나 이 편리한 기능은 C API에서까지 사용할 수는 없습니다. 그러므로 직접 우리가 생성된 PyObject 마다 레퍼런스 카운팅을 해 주어야 합니다. ''Py_INCREF()'', ''Py_DECREF()'', 함수들은 다 그런 레퍼런트 카운팅을 위해 존재합니다!
한편 [[http://docs.python.org/2/c-api/list.html#PyList_SetItem|PyList_SetItem()]], [[http://docs.python.org/2/c-api/tuple.html#PyTuple_SetItem|PyTuple_SetItem()]]이 두 함수는 레퍼런스 카운팅을 자기가 차지합니다.
=== 두번째 예제 코드 ===
이제 소스 코드를 볼께요. 간단한 함수 호출 하나를 하는데 좀 많이 난리를 쳐야 합니다.
[[http://docs.python.org/2/extending/embedding.html#pure-embedding|원래의 소스 코드]]와는 달리 메모리 NULL 체크들은 생략했습니다. 물론 실전에서는 해서는 안 될 방법이지만, 핵심적은 흐름을 보다 명확히 보기 위해서입니다.
위 Makefile에 ''TAR'' 변수에 ''call.out''을 추가해주세요.
#include
int main(int argc, char** argv)
{
int i;
PyObject *pModule, *pFunc;
PyObject *pArgs, *pValue;
if (argc < 3) {
fprintf(stderr, "Usage: call.out pythonfile function [args]\n");
return 1;
}
Py_SetProgramName(argv[0]);
Py_Initialize();
/* modified part */
PyRun_SimpleString(
"import sys\n"
"sys.path.append('.')\n");
pModule = PyImport_ImportModule(argv[1]);
pFunc = PyObject_GetAttrString(pModule, argv[2]);
pArgs = PyTuple_New(argc - 3);
for(i = 0; i < argc - 3; ++i) {
pValue = PyInt_FromLong(atoi(argv[i+3]));
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
printf("Result of call: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pArgs);
Py_DECREF(pValue);
Py_DECREF(pFunc);
Py_DECREF(pModule);
Py_Finalize();
return 0;
}
if 블록을 다 제거하여 훨씬 보기는 편합니다. 원래 예제 코드와 다른 점은 바로 이 부분입니다.
PyRun_SimpleString("import sys\n"
"sys.path.append('.')\n");
pModule = PyImport_ImportModule(argv[1]);
처음 ''PyRun_SimpleString()''은 현재 디렉토리도 모듈 검색 범위에 넣도록 하기 위해 추가된 것입니다. 아마 ''multiply.py'' 파일은 대개 이 소스 코드와 같은 경로에 두고 있을 것입니다. 그런데 이 코드를 넣지 않으면 아마 에러가 날 수도 있습니다. 그리고 원래 소스는 ''PyObject *pName''을 선언하여 argv[1]을 파이썬의 문자열 형태로 만듭니다. 그리고 ''Py_DECREF()''를 호출하지요. 그렇지만 char* 형태를 입력으로 받는 ''PyImport_ImportModule()''이 있으므로 이것으로 갈음할 수 있습니다.
make
./call.out multiply multiply 3 5
Will compute 3 times 5
Result of call: 15
==== 세번째 예제 ====
세번째 예제는 조금 더 다양하게 가 보도록 하죠. urllib을 이용해 웹페이지의 소스 코드를 가져와, 외부 링크 즉, ''http...''로 시작되는 URL을 가져오도록 합니다.
#!/usr/bin/python
import urllib
import re
href_expr = re.compile(r'
이 모듈은 이렇게 사용하겠죠.
import count_href
if __name__ == '__main__':
counter = count_href.count_href()
counter.count('http://www.google.com/en')
counter.count('http://www.daum.net/')
counter.count('http://www.naver.com/')
result = counter.get_result()
for item in result:
print "URL: " + item["url"]
print len(item["links"])
#for link in item["links"]:
# print link
이 모듈의 클래스를 C 코드에서 가져오도록 합니다.
#include
#include
void extract(PyObject* instance)
{
PyObject *returned_object;
Py_ssize_t i, list_size;
returned_object = PyObject_CallMethod(instance, "get_result", NULL);
/* returned_object: list of dicts.
every dict has keys: url, links
links is also list */
list_size = PyList_Size(returned_object);
for(i = 0; i < list_size; ++i) {
PyObject *dict_item, *url, *links;
Py_ssize_t links_size, j;
dict_item = PyList_GetItem(returned_object, i);
assert(dict_item != NULL);
url = PyDict_GetItemString(dict_item, "url");
assert(url != NULL);
links = PyDict_GetItemString(dict_item, "links");
assert(links != NULL);
links_size = PyList_Size(links);
printf("url: %s\t", PyString_AsString(url));
printf("%d entries\n", (int)links_size);
for(j = 0; j < links_size; ++j) {
PyObject *entry_item = PyList_GetItem(links, j);
assert(entry_item != NULL);
printf("%s\n", PyString_AsString(entry_item));
}
Py_DECREF(returned_object);
}
}
int main(int argc, char** argv)
{
int i;
PyObject *module, *class, *instance;
int size;
if(argc < 2) {
fprintf(stderr, "Usage: count_href.out [URLS...]\n");
return 1;
}
Py_Initialize();
PyRun_SimpleString(
"import sys\n"
"sys.path.append('.')\n");
module = PyImport_ImportModule("count_href");
assert(module != NULL);
class = PyObject_GetAttrString(module, "count_href");
assert(class != NULL);
instance = PyObject_CallObject(class, NULL);
assert(instance != NULL);
for(i = 1; i < argc; ++i) {
printf("count_href: %s\n", argv[i]);
PyObject_CallMethod(instance, "count", "s", argv[i]);
}
extract(instance);
Py_Finalize();
return 0;
}
==== 정리 ====
* 프로그램 시작: Py_SetProgramName(선택적), Py_Initialize
* 모듈 불러오기
* PyImport_Import: PyObject* 를 사용
* PyImport_ImportModule: char* 를 사용
* 주의! 모듈 경로에 현재 디렉토리가 포함되지 않음.
* 해결책
- setenv("PYTHONPATH", ".", 1)
- PyRun_SimpleString("import sys\n" "sys.path.append('.')\n");
* 모듈에서 객체(클래스, 함수) 불러오기
* PyObject_GetAttrString
* 호출 가능한(callable) 객체 부르기
* PyObject_Call: callable에 tuple arg, dictionary kw 인자를 넘김
* PyObject_CallObject: tuple args 인자를 넘김
* PyObject_CallFunction: C fomat을 사용하여 호출
* PyObject_CallMethod: object의 method를 호출
* PyObject_CallFunctionObjArgs: CallFunction과 동일하나 PyObject*를 인자로 넘김
* PyObject_CallMethodObjArgs: CallMethod와 동일하나 PyObject*를 인자로 넘김
* 값 가져오기
* Int, Long, Float, Complex, String: Py[python_type]_As[c_type]
* Dictionary, List: PyDict_GetItem, PyList_GetItem
* 값 설정하기
* Int, Long, Float, Complex, String: Py[python_type]_From[c_type]
* Dictionary, List: PyDict_SetItem, PyList_SetItem
* 레퍼런스 설정하기
* Py_INCREF, Py_DECREF: 레퍼런스 카운트 증가, 감소
* Py_CLEAR: 레퍼런스 카운트를 없앰
* 프로그램 종료: Py_Finalize
===== boost.python 사용하기 =====
C API를 활용하여 원하는 기능을 구현할 수도 있지만, 간단한 데이터를 가져오는데도 상당히 코드가 많이 필요합니다. API를 간단히 파악하는 정도로 두고, 보다 간결하고 편리하게 쓸 수 있는 라이브러리를 찾아야 할 것 같습니다.
[[https://wiki.python.org/moin/IntegratingPythonWithOtherLanguages | 파이썬 위키]]에 다른 언어와 파이썬을 연동하는 방법이 잘 나와 있습니다. 여기서는 C++의 대표적인 라이브러리인 [[http://www.boost.org/| Boost C++ Libraries]]를 사용하도록 하겠습니다.
CC = /usr/bin/g++
PYTHON_CONFIG = /opt/local/bin/python2.7-config
BOOST_INC_PATH = /opt/local/include
BOOST_LIB_PATH = /opt/local/lib
CFLAGS = `$(PYTHON_CONFIG) --cflags` -I $(BOOST_INC_PATH)
LDFLAGS = `$(PYTHON_CONFIG) --ldflags` -L $(BOOST_LIB_PATH) -lboost_python-mt
TAR = test.out hello_py.out # 여기에 .out 파일을 추가하세요
OBJ = $(TAR:.out=.o)
SRC = $(TAR:.out=.cpp)
all: $(TAR)
.o.out: $(OBJ)
$(CC) $(LDFLAGS) -o $@ $<
.cpp.o: %.cpp
$(CC) $(CFLAGS) -c $<
clean:
rm -rf $(TAR) $(OBJ)
==== 첫번째 boost.python 예제 ====
#include
int main(int argc, char** argv)
{
Py_Initialize();
boost::python::exec("print \'Hello, World!\'\n");
Py_Finalize();
return 0;
}
현재는 별다른 것이 없어 보이네요
==== 두번째 boost.python 예제 ====
#include
#include
namespace bp = boost::python;
void workaround_for_local_modules()
{
PyRun_SimpleString(
"import sys\n"
"sys.path.append('.')\n");
}
int main(int argc, char** argv)
{
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_Initialize();
workaround_for_local_modules();
try {
bp::object module_name;
bp::object module;
bp::object func;
module_name = bp::object(bp::handle<>(PyString_FromString(argv[1])));
module = bp::object(bp::handle<>(PyImport_Import(module_name.ptr())));
func = module.attr(argv[2]);
if(func && PyCallable_Check(func.ptr())) {
bp::object tuple;
tuple = bp::object(bp::handle<>(PyTuple_New(argc - 3)));
for(int i = 0; i < argc - 3; ++i) {
PyObject* arg;
arg = PyInt_FromLong(atoi(argv[i+3]));
PyTuple_SetItem(tuple.ptr(), i, arg);
}
bp::object valueObj;
int value;
valueObj = bp::object(bp::handle<>(PyObject_CallObject(func.ptr(), tuple.ptr())));
value = bp::extract(valueObj);
std::cout << value << std::endl;
}
} catch(bp::error_already_set const &) {
PyErr_Print();
}
Py_Finalize();
return EXIT_SUCCESS;
}
''PyObject''가 ''boost::python::object''로 래핑되어 있습니다. 또한 ''boost::python::handle<>''을 이용하면 ''PyObject''의 레퍼런스를 관리해 줍니다. ''boost::python''의 대부분의 기능은 extending에 초점이 맞춰져 있고 embedding에는 그다지 많은 기능을 제공하지 않는 편이므로 상당히 많은 부분에서 C API를 그대로 가져와 사용해야 합니다.
==== 세번째 boost.python 예제 ====
===== 참고 사이트 =====
* [[http://docs.python.org/2/extending/embedding.html|Embedding Python in Another Application]]
* [[https://wiki.python.org/moin/IntegratingPythonWithOtherLanguages | Integrating Python With Other Languages]]
* [[http://www.boost.org/doc/libs/1_55_0/libs/python/doc/index.html | Boost.Python Index]]