파이썬 마을 게시판 인덱스 파이썬 마을
우리나라 파이썬 사용자들의 이야기 마을
 
 FAQFAQ   검색검색   멤버리스트멤버리스트   사용자 그룹사용자 그룹   사용자 등록하기사용자 등록하기 
 개인 정보개인 정보   비공개 메시지를 확인하려면 로그인하십시오비공개 메시지를 확인하려면 로그인하십시오   로그인로그인 
Google
python.or.kr Web

[SWIG강좌] 3.4 Typemap (5)

 
글 쓰기   답변 달기    파이썬 마을 게시판 인덱스 -> 파이썬 팁/강좌/모듈소개 모음
이전 주제 보기 :: 다음 주제 보기  
글쓴이 메시지
jrcho



가입:
올린 글: 56

올리기올려짐: 2004 5월 12 7:45 pm    주제: [SWIG강좌] 3.4 Typemap (5) 인용과 함께 답변

3.4.6. Advanced Typemap

(1) 파일 입출력

예를 들어 C++ 함수에

void save(FILE *f);

와 같이 FILE 구조체의 포인터를 입력받아 이 파일에 쓰는 함수를 생각해 보자. 아마도 Python에서 자연스럽게 사용하는 것은

>>> file = open("xxx.dat","w")
>>> save(file)

과 같은 형태일 것이다. 이때 사용할 수 typemap은 다음과 같다.

코드:

// Type mapping for grabbing a FILE * from Python
%typemap(python,in) FILE * {
  if (!PyFile_Check($input)) {
      PyErr_SetString(PyExc_TypeError, "Need a file!");
      return NULL;
  }
  $1 = PyFile_AsFile($input);
}


(2) C++에서 Python 함수 이용
C++ 코드에서 Python 함수를 이용해야 할 필요가 있다. 즉, Python callback함수를 사용하는 것이다. 예를 들어 다음과 같은 코드를 생각해 보자.

코드:

typedef double (*PLOTFUNC)(double);

static PLOTFUNC    _callback   = 0;    // Callback function

void set_method(PLOTFUNC func)        // Set callback method
{
  _callback = func;
}

void plot()                         // Make a plot
{
  printf("plot() in...\n");
  for(int i=0;i<some_range;i++)
  {
    double x = i;
    double y = (*_callback)(x);
    ...plot line with x, y pair
  }
}


C++에서의 사용은

코드:

double func(double x)
{
  return x*x+0.5x;
}

void main()
{
  set_method(func);
  plot(); 
}


와 같이 될 것이다. 이제 Python에서 사용하고 y좌표를 계산하는 함수를 Python에서 정의하려면 어떻게 해야 할 까?

코드:

%module example
%{

typedef double (*PLOTFUNC)(double);

static PLOTFUNC    _callback   = 0;    // Callback function

void set_method(PLOTFUNC func)        // Set callback method
{
  _callback = func;
}

void plot()                         // Make a plot
{
  printf("plot() in...\n");
  for(int i=0;i<3;i++)
  {
    double x = i;
    double y = (*_callback)(x);
    printf("%f %f\n",x,y);
  }
}


%}

// Grab a Python function object as a Python object.
%typemap(python,in) PyObject *pyfunc {
  if (!PyCallable_Check($input)) {
      PyErr_SetString(PyExc_TypeError, "Need a callable object!");
      return NULL;
  }
  $1 = $input;
}

%{
static PyObject* _pyfunc = 0;

static double PythonCallBack(double a)
{
   PyObject *func, *arglist;
   PyObject *result;
   double    dres = 0;
   
   func = (PyObject *) _pyfunc;               // Get Python function
   arglist = Py_BuildValue("(d)",a);             // Build argument list
   result = PyEval_CallObject(func,arglist);     // Call Python
   Py_DECREF(arglist);                           // Trash arglist
   if (result) {                                 // If no errors, return double
     dres = PyFloat_AsDouble(result);
   }
   Py_XDECREF(result);
   return dres;
}

void set_pymethod(PyObject* pyfunc)
{
   set_method(PythonCallBack);
   _pyfunc = pyfunc;
   Py_INCREF(pyfunc);
}

%}

void set_pymethod(PyObject* pyfunc);
void plot();                                   


Python 함수 주소를 나타내는 static 변수(_pyfunc), set_pymethod(), PythonCallBack() 이라는 함수를 만들어 준다. set_pymethod()에서는 Python 함수의 주소를 저장하고, PythonCallBack() 함수의 주소를 C++의 set_method로 등록한다. plot()을 호출한면 등록된 PythonCallBack() 함수를 이용하고 이 함수안에서는 등록된 Python 함수를 수행한다.

위 예는 아주 간단한 Callback 함수의 구현이다. 보다 세련된 예를 보기로 한다. 간단한 C++ 2D plotting widget을 작성한다고 하고, 클래스의 구조는 다음과 같다.

코드:

// PlotWidget.h

typedef double (*PLOTFUNC)(double, void *);

class PlotWidget {
private:
  double      xmin,ymin,xmax,ymax;         // Plotting range
  PLOTFUNC    callback;                    // Callback function
  void       *clientdata;                  // Client data for callback
  int         npoints;                     // Number of points to plot
  int         width;                       // Image width
  int         height;                      // Image height
  int         black,white;                 // Some colors
  gdImagePtr  im;                          // Image pointer
  void        transform(double,double,int&,int&);
public:
  PlotWidget(int w, int h,double,double,double,double);
  ~PlotWidget();
  void set_method(PLOTFUNC func, void *clientdata)    // Set callback method
  {
     this->callback = func;
     this->clientdata = clientdata;
  }
  void set_range(double,double,double,double);         // Set plot range
  void set_points(int np) {npoints = np;}              // Set number of points
  void plot()                                            // Make a plot
  {
     use like this :  double y = (*callback)(x,clientdata);
                    // double PythonCallBack(double a, void *clientdata)가 수행됨
  }

  void save(FILE *f);                                  // Save a plot to disk
};


이 위젯을 C++에서 사용된다면, 다음과 같을 것이다.

코드:

// Simple main program to test out our widget
#include <stdio.h>
#include "widget.h"
#include <math.h>

// Callback function
double my_func(double a, void *clientdata)
{
  return sin(a);
}

int main(int argc, char **argv)
{
  PlotWidget *w;
  FILE *f;
  w = new PlotWidget(500,500,-6.3,-1.5,6.3,1.5);
  w->set_method(my_func,0); // Set callback function
  w->plot(); // Make plot
  f = fopen("plot.gif","w");
  w->save(f);
  fclose(f);
  printf("wrote plot.gif\n");
}


이제 이 위젯을 Python에서 interactive하게 이용하려고 한다. SWIG에서 다음과 같이 interface 파일을 작성한다.

코드:

// example.i
// SWIG interface to our PlotWidget
%module plotwidget
%{

typedef double (*PLOTFUNC)(double, void *);

class PlotWidget {
private:
  double      xmin,ymin,xmax,ymax;         // Plotting range
  PLOTFUNC    callback;                    // Callback function
  void       *clientdata;                  // Client data for callback
  int         npoints;                     // Number of points to plot
  int         width;                       // Image width
  int         height;                      // Image height
  int         black,white;                 // Some colors
  gdImagePtr  im;                          // Image pointer
  void        transform(double,double,int&,int&);
public:
  PlotWidget(int w, int h,double,double,double,double);
  ~PlotWidget();
  void set_method(PLOTFUNC func, void *clientdata)    // Set callback method
  {
     this->callback = func;
     this->clientdata = clientdata;
  }
  void set_range(double,double,double,double);         // Set plot range
  void set_points(int np) {npoints = np;}              // Set number of points
  void plot()                                            // Make a plot
  {
     use like this :  double y = (*callback)(x,clientdata);
                    // double PythonCallBack(double a, void *clientdata)가 수행됨
  }

  void save(FILE *f);                                  // Save a plot to disk
};

%}

// Grab a Python function object as a Python object.
%typemap(python,in) PyObject *pyfunc {
  if (!PyCallable_Check($input)) {
      PyErr_SetString(PyExc_TypeError, "Need a callable object!");
      return NULL;
  }
  $1 = $input;
}

// Type mapping for grabbing a FILE * from Python
%typemap(python,in) FILE * {
  if (!PyFile_Check($input)) {
      PyErr_SetString(PyExc_TypeError, "Need a file!");
      return NULL;
  }
  $1 = PyFile_AsFile($input);
}

%{
/* This function matches the prototype of the normal C callback
   function for our widget. However, we use the clientdata pointer
   for holding a reference to a Python callable object. */
static double PythonCallBack(double a, void *clientdata)
{
   PyObject *func, *arglist;
   PyObject *result;
   double    dres = 0;
   
   func = (PyObject *) clientdata;               // Get Python function
   arglist = Py_BuildValue("(d)",a);             // Build argument list
   result = PyEval_CallObject(func,arglist);     // Call Python
   Py_DECREF(arglist);                           // Trash arglist
   if (result) {                                 // If no errors, return double
     dres = PyFloat_AsDouble(result);
   }
   Py_XDECREF(result);
   return dres;
}
%}

// Grab the class definition
#include <stdio.h>
extern "C" {
#include "gd.h"
}

typedef double (*PLOTFUNC)(double, void *);

class PlotWidget {
public:
  PlotWidget(int w, int h,double,double,double,double);
  ~PlotWidget();
  void set_method(PLOTFUNC func, void *clientdata);    // Set callback method
  void set_range(double,double,double,double);         // Set plot range
  void set_points(int np) {npoints = np;}              // Set number of points
  void plot();                                         // Make a plot
  void save(FILE *f);                                  // Save a plot to disk
%extend {
   // Set a Python function object as a callback function
   // Note : PyObject *pyfunc is remapped with a typempap
   void set_pymethod(PyObject *pyfunc) {
     self->set_method(PythonCallBack, (void *) pyfunc);
     Py_INCREF(pyfunc);
   }
}

};


Python에서 사용하는 방법은 다음과 같다.

코드:

from plotwidget import *
from math import *

# Make a plot using a normal Python function as a callback
def func1(x):
  return 0.5*sin(x)+0.25*sin(2*x)+0.125*cos(4*x)

print "Making plot1.gif..."

# Make a widget and set callback
w = PlotWidget(500,500,-10,-2,10,2)
w.set_pymethod(func1) # Register our Python function
w.plot()
f = open("plot1.gif","w")
w.save(f)
f.close()

# Make a plot using an anonymous function
print "Making plot2.gif..."
w1 = PlotWidget(500,500,-4,-1,4,16)
w1.set_pymethod(lambda x: x*x) # Register x^2 as a callback
w1.plot()
f = open("plot2.gif","w")
w1.save(f)
f.close()

# Make another plot using a built-in function
SWIG Users Guide SWIG and Python 206
print "Making plot3.gif..."
w2 = PlotWidget(500,500,-7,-1.5,7,1.5)
w2.set_pymethod(sin) # Register sin(x) as a callback
w2.plot()
f = open("plot3.gif","w")
w2.save(f)
f.close()


위에서 “plot” 메쏘드는 C++로만 작성되어 있고, 또한 C/C++로 작성된 callback 함수를 호출한다고 가정한다.

... 이것으로 [SWIG강좌]를 모두 마침니다. 나머지 필요한 부분은 SWIG 매뉴얼을 찾아보십시오. 매뉴얼에서 찾을 수 없는 것들은 new group을 뒤져야 합니다.....
위로
사용자 정보 보기 비밀 메시지 보내기    
이전 글 표시:   
글 쓰기   답변 달기    파이썬 마을 게시판 인덱스 -> 파이썬 팁/강좌/모듈소개 모음 시간대: GMT + 9 시간(한국)
페이지 11

 
건너뛰기:  
새로운 주제를 올릴 수 없습니다
답글을 올릴 수 없습니다
주제를 수정할 수 없습니다
올린 글을 삭제할 수 없습니다
투표를 할 수 없습니다



Powered by phpBB © 2001, 2005 phpBB Group
회선/장비: Daum DNA , 관리: 장혜식,서상현