• No results found

Python erweitern in C und C++

N/A
N/A
Protected

Academic year: 2021

Share "Python erweitern in C und C++"

Copied!
27
0
0

Loading.... (view fulltext now)

Full text

(1)

Python erweitern in C und C++

Robert Franke

DESY Zeuthen und Humboldt Universität Berlin Berlin, 18.02.2010

(2)

Inhalt

1 Einführung 2 Ctypes 3 Python API 4 Cython 5 SWIG 6 Boost.Python

(3)

Einführung

Warum C/C++?

Performance

Wrappen existierender Bibliotheken Verteilen von proprietärem Code

(4)

Ctypes

Was ist ctypes

einfachstes Interface zu C-Bibliotheken in Standard Library seit Python 2.5 Basiert auf libffi für call conventions

keine Änderung/Ergänzung der C-Bibliothek nötig! Automatische Typumwandlung von Argumenten Unterstützt Pointer, Structs, Unions

(5)

Ctypes

Wrappen von sqrt aus libm.so

importctypes

importmath

libm=ctypes.cdll.LoadLibrary(’libm.so’)

sqrt=libm.sqrt

sqrt.restype=ctypes.c_double sqrt.argtypes= [ctypes.c_double] printsqrt(3.2),math.sqrt(3.2)

(6)

Ctypes

Arbeiten mit Structs

#include<stdlib.h> structdoublearray{

unsigned long longlength;

double*array; };

doublesum(structdoublearray*arr){

doubles=0.;

unsigned long longi;

for(i=0;i<arr->length;i++){ s+=arr->array[i]; }

returns; }

(7)

Ctypes

importctypes importrandom

classDOUBLEARRAY(ctypes.Structure):

_fields_= [("length",ctypes.c_ulonglong),

("array",ctypes.POINTER(ctypes.c_double))]

libdoublearray=ctypes.cdll.LoadLibrary("./doublearray.so")

libdoublearray.sum.argtypes= [ctypes.POINTER(DOUBLEARRAY)]

libdoublearray.sum.restype=ctypes.c_double doublearray=ctypes.c_double*100

array=doublearray()

foriinxrange(0,100):

array[i] =random.random()

carray=DOUBLEARRAY(100,array)

(8)

Python API

Die Python API

Low-Level Interface

Manuelles Reference Counting Wenig Overhead

(9)

Python API

Kubikwurzel

#include<Python.h>

#include<math.h> staticPyObject*ErrorObject;

staticPyObject*cubic_root(PyObject*self,PyObject*args){

doubleguess=1.0;

doubleN;

if(!PyArg_ParseTuple(args,"d", &N))

return0;

while(fabs((guess*guess*guess-N)/N) >1e-8){ guess=1./3* (2*guess+N/(guess*guess)); }

returnPy_BuildValue("d",guess); }

(10)

Python API

Kubikwurzel (2)

staticcharcubic_root__doc__[] ="Approximate the cubic root with the Babylonian method";

staticPyMethodDefcubicmethods[] ={

{"cubic_root",cubic_root,METH_VARARGS,cubic_root__doc__}, {NULL,NULL,0,NULL}

};

voidinitcubic(void){

PyObject*m, *d;

m=Py_InitModule("cubic",cubicmethods); d=PyModule_GetDict(m);

ErrorObject=Py_BuildValue("s","cubic module error"); PyDict_SetItemString(d,"error",ErrorObject);

if(PyErr_Occurred())

Py_FatalError("Can’t initialize module cubic!"); }

(11)

Python API

setup.py

fromdistutils.coreimportsetup,Extension setup(name="cubic",

version="1.0",

maintainer="Robert Franke",

maintainer_email="[email protected]",

description="Sample, simple Python extension module",

ext_modules= [Extension(’cubic’,sources=[’cubic.c’])] )

(12)

Python API

Eine Liste von Zufallszahlen

#include<Python.h>

#include<stdlib.h>

#include<time.h>

staticPyObject*ErrorObject;

staticPyObject*random_list(PyObject*self,PyObject*args){

longnrand,i;

doubled;

if(!PyArg_ParseTuple(args,"l", &nrand))

return0;

PyObject*list=PyList_New(nrand);

for(i=0;i<nrand;i++){

d=drand48();

PyObject*listitem=Py_BuildValue("d",d);

PyList_SET_ITEM(list,i,listitem); }

returnlist; }

staticPyObject*wrap_drand48(PyObject*self,PyObject*args){

doubled;

(13)

Python API

Eine Liste von Zufallszahlen (2)

staticcharwrap_drand__doc__[] ="A wrapper around the libc drand48 function";

staticcharrandom_list__doc__[] ="Generate a list of random numbers";

staticPyMethodDefrandommethods[] ={

{"random",wrap_drand48,METH_VARARGS,wrap_drand__doc__}, {"random_list",random_list,METH_VARARGS,random_list__doc__}, {NULL,NULL,0,NULL}

};

voidinitmyrandom(void){

PyObject*m, *d;

m=Py_InitModule("myrandom",randommethods); d=PyModule_GetDict(m);

ErrorObject=Py_BuildValue("s","myrandom module error"); PyDict_SetItemString(d,"error",ErrorObject);

if(PyErr_Occurred())

Py_FatalError("Can’t initialize module myrandom!"); srand48(time(0));

(14)

Python API

Reference counting

Python nutzt reference counting zum Speichermanagement Owned reference vs. borrowed reference

Py_INCREF: erhöht reference count

Py_DECREF: erniedrigt reference count, löscht Objekt wenn

count==0

die meisten API Funktionen rufen INCREF für die Objekt , die sie zurückgeben

Ausnamhme u.a.: PyListi_GetItem, PyTuple_GetItem Quelle von Crashs und Memory Leaks!

(15)

Python API

Shallow list copy

#include<Python.h>

#include<stdlib.h>

staticPyObject*ErrorObject;

staticPyObject*copy_list(PyObject*self,PyObject*args){ Py_ssize_tlen,i;

PyObject*list;

PyArg_ParseTuple(args,"O",&list);

if(!PyList_Check(list)){

PyErr_SetString(PyExc_TypeError,"expected list type");

returnNULL; }

len=PyList_Size(list);

PyObject*new_list=PyList_New(len);

for(i=0;i<len;i++){

PyObject*listitem=PyList_GetItem(list,i);

Py_INCREF(listitem);//Important as PyList_GetItem does not //increment the refcount!

PyList_SET_ITEM(new_list,i,listitem); }

returnnew_list; }

(16)

Python API

Shallow list copy (2)

staticcharcopy_list__doc__[] ="Make a shallow list copy";

staticPyMethodDefcopy_listmethods[] ={

{"copy",copy_list,METH_VARARGS,copy_list__doc__}, {NULL,NULL,0,NULL}

};

voidinitcopy_list(void){ PyObject*m, *d;

m=Py_InitModule("copy_list",copy_listmethods);

d=PyModule_GetDict(m);

ErrorObject=Py_BuildValue("s","copy_list module error");

PyDict_SetItemString(d,"error",ErrorObject);

if(PyErr_Occurred())

Py_FatalError("Can’t initialize module copy_list!"); }

(17)

Cython

Was ist Cython?

Python mit Typen vorher: Pyrex

Methoden werden mit Typdeklarationen angereichert Cython macht daraus C-Code, den man dann kompiliert

(18)

Cython

Kubikwurzel

frommathimportfabs

defcubic_root(double f):

cdef double x=1.5# Start value

whilefabs((x*x*x-f)/f) >1e-8:

x= (2*x+f/(x*x))/3.

(19)

SWIG

Was ist SWIG?

Simplified Wrapper and Interface Generator

Wrappergenerator für viele Sprachen: Python, Perl, Ruby, TCL, Common List, C#, etc.

Unterstützt C und C++ Definitionen in Interface-Files

Oft können Header direkt als Interface Deklarationen benutzt werden

(20)

SWIG

Kubikwurzel

%module cubic

%{

externdoublecubic_root(double);

%}

(21)

Boost.Python

Was ist Boost.Python

Teil der Boost C++-Bibliothek

Entwickelt von Dave Abrahams et al.

Aktuell: Boost 1.42.0, Version 2 von Boost.Python

Unterstützt Funktionen, Memberfunktionen, Klassenfunktionen, Docstrings, Properties, Overloading, Keywordargumente, Defaultargumente, Serialization etc.

(22)

Boost.Python

Kubikwurzel

#include<boost/python.hpp>

#include<cmath>

using namespaceboost::python;

doublecubic_root(constdoubleN){

doubleguess=1.0;

while(std::fabs((guess*guess*guess-N)/N) >1e-8){ guess=1./3* (2*guess+N/(guess*guess));

}

returnguess;

}

BOOST_PYTHON_MODULE(cubic){ def("cubic_root",&cubic_root);

(23)

Boost.Python Ein Wrapper um boost::gil

#include<stdexcept>

#include<boost/filesystem.hpp> // includes all needed Boost.Filesystem declarations

#include"image.h"

using namespaceboost::gil;

using namespaceboost::filesystem;

using namespacestd;

usingboost::shared_ptr;

Image::Image(conststd::string&path){

if(!exists(path)){

throwstd::runtime_error("File does not exist"); }

jpeg_read_image(path,img_);

img_view_=view(img_); }

shared_ptr<Pixel>Image::at(constintx,constinty)const{

rgb8c_view_t::iteratorit=img_view_.at(x,y);

Pixel*px=newPixel((*it)[0],(*it)[1],(*it)[2]);

returnshared_ptr<Pixel>(px); }

unsigned intImage::width()const{

return static_cast<unsigned int>(img_view_.width()); }

(24)

Boost.Python

Ein Wrapper um boost::gil (2)

#include<boost/python.hpp>

#include<string>

#include"image.h"

using namespaceboost::python;

usingboost::shared_ptr;

usingstd::string;

BOOST_PYTHON_MODULE(pyimage){

class_<Pixel,shared_ptr<Pixel> >("Pixel",init<short,short,short>()) .def_readwrite("red",&Pixel::r_)

.def_readwrite("green",&Pixel::g_) .def_readwrite("blue",&Pixel::b_) ;

class_<Image>("Image",init<string>()) .def("width",&Image::width) .def("height",&Image::height) .def("at",&Image::at) ;

(25)

Boost.Python

Callbacks in C++ und Python

#include"callback.h"

#include<boost/foreach.hpp>

doublemapsum(conststd::vector<double>&vec,map_func_typefunc){

doublesum=0;

BOOST_FOREACH(doubled,vec){ sum+=func(d);

}

returnsum;

}

doublesquare(constdoubled){

returnd*d;

(26)

Boost.Python

Callbacks in C++ und Python (2)

#include<boost/python.hpp>

#include<boost/python/suite/indexing/vector_indexing_suite.hpp>

#include"callback.h"

#include"py_boost_function.hpp"

#include"container_conversions.h"

map_func_typesquare_ptr(square);

using namespaceboost::python;

using namespacescitbx::boost_python::container_conversions;

BOOST_PYTHON_MODULE(callback){

boost::python::class_<std::vector<double>,boost::shared_ptr<std::vector<double> > >("PyVec") .def(boost::python::vector_indexing_suite<std::vector<double> >());

from_python_sequence<std::vector<double>,variable_capacity_policy>();

def("reduce",&mapsum);

def_function<double(constdouble)>(

"map_func_t",

"A function"

);

scope().attr("square") =square_ptr; }

(27)

Boost.Python

Dokumentation und Links

http://docs.python.org/c-api/ http://docs.python.org/library/ctypes.html http://www.swig.org/doc.html http://www.boost.org/doc/libs/1_42_0/libs/ python/doc/index.html http://wiki.python.org/moin/boost.python/HowTo http://edcjones.tripod.com/refcount.html

References

Related documents

We may regard the CWFT as a linear TV band-pass filter element of a filter-bank spectrum analyzer and, therefore, the TV spectrum obtained by the CWFT can also be interpreted as

[r]

Midterm exam results and homework grades will make up term time grade, which will be added to the contribution of the final exam result to determine the course grade.

The Central Processing Unit (CPU) performs program control and data processing Storage devices include memory and secondary storage (e.g., a USB Flash Drive).

These examples show how you can find elements from practically any sector, analyze them for similarities and differences and then write a joke bringing these two facets together.

Function: To provide a record of general administration of the Property Assessment Department as carried out by the City Assessor Description: Correspondence, reports,

•  Python runtime executed in our C++ wsgate plugin. – 

According to the definition by COSO in 1992, an internal control system is defined as a set of methods, designed and controlled by senior management and board of directors