 |
파이썬 마을 우리나라 파이썬 사용자들의 이야기 마을
|
|
| 이전 주제 보기 :: 다음 주제 보기 |
| 글쓴이 |
메시지 |
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을 뒤져야 합니다..... |
|
| 위로 |
|
 |
|
|
새로운 주제를 올릴 수 없습니다 답글을 올릴 수 없습니다 주제를 수정할 수 없습니다 올린 글을 삭제할 수 없습니다 투표를 할 수 없습니다
|
|