Unix

Python 3.2 Embedding 예제

알 수 없는 사용자 2012. 3. 20. 22:46
어려웠다 -_-;; Reference Manual을 잘 참조하는 습관을 들여야 한다... 

struct_lib.py :
#!/usr/bin/python3
import sys
import re

###
### struct node
### 이런 멤버변수가 대충 있다. 
###
class Node:
def __init__(self):
self.level = 0 # hops from root.
self.name = ""
self.ty = ""
self.x = 0
self.y = 0
self.net = ""
self.fanout = 0
self.dist = 0.0 # distance from the root node
self.arr = 0.0 # clock signal arrival time, picosec.

self.par = None # A parent node
self.children = [] # list of child nodes

... 중략 ...

# 이런 함수가 있다.
def load_struct( fname ) :
f = open( fname, 'r' )

nodes = [] # list of nodes

# Parse input
for line in f.readlines():
line = line.strip()
# sometime A->Z[ like stuck braces occur. split them.
line = line.replace("[", " [")

# find all word without white space or [...], a group enclosed by [].
match = re.findall('\[[^\]]*\]|\S+', line)

# set node info from the regexp match.
if is_node( match ) :
node = Node()
node.set_info( match )
nodes.append(node)

f.close()

## print all nodes
#for n in nodes :
# n.print()
# print( "" )

# resolve parent-child relations
for i in range(len(nodes)) :
node = nodes[i]
par = find_parent( i, nodes )
if par != None :
par.add_child( node )

root = nodes[0]

# Calculate dist and hops from root
bfs( root, 0 )

# print the tree structure for testing.
# root.print_tree()

return (root,nodes)


load_struct 함수를 돌려서 그 결과물로서 메모리로 읽힌 Nodes 클래스 인스턴스들의 멤버변수들을 읽어오고 싶은거다. 즉... C++에서 load_struct 함수를 돌리고, 그 리턴값인 (root, nodes) 중, 리스트인 nodes 에 든 각 node에 대해서 , node.name 을 화면에 출력하는 함수를 짜고 싶다.

Makefile :
 test: a.out                                                                     
                                                                                
                                                                                
# Run python3.2-config --ldflags command to get required flags!                 
PYTHON_LDFLAGS=-L/usr/lib/python3.2/config-3.2mu \                              
    -lpthread -ldl -lutil -lm -lpython3.2mu \                                   
    -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions                   
                                                                                
# Run python3.2-config --cflags command to get required flags!                  
PYTHON_CFLAGS=-I/usr/include/python3.2mu -g -fwrapv -Wall                       
                                                                                
# You must put linking flag AFTER the input source code...                      
a.out: main.cpp                                                                 
    g++ ${PYTHON_CFLAGS} main.cpp ${PYTHON_LDFLAGS}  
컴파일 하는 것 조차도 은근 힘들다 -_-;;

이제 대망의 main.cpp:
#include <Python.h>
#include <iostream>

using namespace std;



int main( int argc, char *argv[] )
{
int ret = 0;
PyObject *pName, *pModule;
Py_Initialize();

// add this directory to path so that struct_lib can be found.
PyRun_SimpleString("import sys"); 
PyRun_SimpleString("sys.path.append(\".\")");

// Import struct_lib.py
pName = PyUnicode_FromString( "struct_lib" );
pModule = PyImport_Import( pName );
Py_DECREF( pName );
if( !pModule ) {
cerr << "Unable to load python module :(" << endl;
ret = 1;
}
else {
// get function we want to call.
PyObject *pFunc = PyObject_GetAttrString( pModule, "load_struct" );
assert( pFunc && PyCallable_Check( pFunc ) );

PyObject *pArgs = PyTuple_New( 1 );
PyObject *pFname = PyUnicode_FromString( "s13207.struct" );
PyTuple_SetItem( pArgs, 0, pFname );

PyObject *pRetval = PyObject_CallObject( pFunc, pArgs );

// get nodes pointer
PyObject *nodes = PyTuple_GetItem( pRetval, 1 );

// iterate through nodes
assert( PyList_Check( nodes ) );
int sz = PyList_Size( nodes );
for( int i = 0 ; i < sz ; ++i ) {
PyObject *node = PyList_GetItem( nodes, i );

// extract a property for test drive!
wchar_t *pName = PyUnicode_AsWideCharString(
PyObject_GetAttrString(node, "name"), NULL );
wcout << pName << endl;
PyMem_Free( pName );
}

// access member variable of root

// pRetval is a tuple that holds (root,nodes).
// We only need root.

// free
Py_DECREF( pRetval );
Py_DECREF( pArgs );
// Py_DECREF( pFname ); What goes into the tuple gets freed
// when the tuple is DECREF'ed.
Py_DECREF( pFunc );
Py_DECREF( pModule );
}



//
// Finalizations
//
if( ret != 0 ) {
PyErr_Print();
}
Py_Finalize();
return ret;
}
 
C++쪽에서 파이선을 불러서 이거저거 작업하긴 진짜... 귀찮고 힘들고 짜증난다. 애초에 Python기반으로 가서 속도가 필요한 부분만 C++로 Extension하는게 낫지, C++에서 Python을 Embedding하는건 힘들다.

의의:
- Python 으로 만든 함수를 콜했다.
- Tuple, List 에 대한 operation도 좀 했다.
- Python으로 된 class member variable의 값을 얻어냈다. (그리고 화면에 출력함).
- API가 업데이트 되면서 wcout 을 쓰게 되는 것도 나름 중요포인트... cout으로 안 되어서.