background image

J

ĘZYK

 PYTHON  

NARZĘDZIE

 

DLA

 

KAŻDEGO

 

NAUKOWCA

 

Marcin Lewandowski  

mlew@ippt.gov.pl

 

background image

ROZSZERZANIE I OSADZANIE PYTHONA 
(PYTHON EXTENDING & EMBEDDING) 

background image

Łączenie i Osadzanie Pythona 

• Łączenie Pythona (Extending) 

– Tworzenie wrapperów do bibliotek w C/C++ 

• Osadzanie Pythona (Embedding) 

– Wywoływanie Pythona z programu C/C++ 

background image

PO CO? 

• Budowa „skryptowalnych” aplikacji C/C++  – nie tylko 

bibliotekę C/C++, ale całą aplikację można zamienid na 

moduł Pythona. Zastępując main() programu C/C++ przez 

interpreter Pythona uzyskujemy aplikację kontrolowaną 

skryptem Pythona!  To pozwala łatwą modyfikację aplikacji 

(bez konieczności jej rekompilacji). 

• Szybkie prototypowanie i debugowanie – 

biblioteka/aplikacja C/C++ pod kontrolą Pythona może byd 

łatwo testowana i debugowana. 

• Integracja systemów/oprogramowania – z pomocą 

Pythona i modułów rozszerzeo można łatwo sklejad 

aplikacje i biblioteki stworzone w różnych językach (nie 

tylko C/C++). Niezależne elementy aplikacje i biblioteki 

można integrowad w jedną nową aplikację. 

background image

Zagadnienia łączenia różnych języków 

programowania 

• typy danych 
• przekazywanie argumentów funkcji 
• tworzenie nowych zmiennych 
• zarządzanie pamięcią 
• obsługa wyjątków 

 

background image

LINKI 

• Extending and Embedding the Python 

Interpreter – dokumentacja Pythona 
(

http://docs.python.org/extending/

) 

• Python/C API – interfejs C do Pythona 

(

http://docs.python.org/c-api/

 

background image

ROZSZERZANIE PYTHONA 

background image

Kompilacja rozszerzenia do Pythona 

• Rozszerzenie (moduł C) można łączyd z 

Pythonem przez: 

– Ładowanie dynamiczne 

• Rozszerzenie jest kompilowane do biblioteki współdzielonej 

(DLL). 

• Polecenie ‘import’ ładuje i inicjalizuje moduł w locie 
• Łatwiejsza kompilacja i stosowane częściej niż łączenie 

statyczne 

– Łączenie statyczne 

• Rozszerzenie jest wkompilowane bezpośrednio w interpreter 

Pythona i staje się nowym modułem wbudowanym (“built-

in”) 

• Polecenie ‘import’ tylko inicjalizuje moduł 

background image

Python/C API 

(plik nagłówkowy Python.h) 

The Very High Level Layer 

Reference Counting 

Exception Handling 

Utilities 

– Operating System Utilities 
– System Functions 
– Process Control 
– Importing Modules 
– Data marshalling support 
– Parsing arguments and building values 
– String conversion and formatting 
– Reflection 

Abstract Objects Layer 

– Object Protocol 
– Number Protocol 
– Sequence Protocol 
– Mapping Protocol 
– Iterator Protocol 
– Old Buffer Protocol 

 

Concrete Objects Layer 

Fundamental Objects 

Numeric Objects 

Sequence Objects 

Mapping Objects 

Other Objects 

 Initialization, Finalization, and Threads 

Thread State and the Global Interpreter Lock 

Profiling and Tracing 

Advanced Debugger Support 

Memory Management 

Object Implementation Support 

Allocating Objects on the Heap 

Common Object Structures 

Type Objects 

Number Object Structures 

Mapping Object Structures 

Sequence Object Structures 

Buffer Object Structures 

Supporting Cyclic Garbage Collection 

background image

Funkcja opakowująca (wrapper) 

Argumenty z 

Pythona 

• Konwersja argumentów na typy C 
• Weryfikacja poprawności argumentów 

Funkcja 

• Wykonanie funkcji na przekazanych 

argumentach 

Rezultaty do 

Pythona 

• Konwersja rezultatów funkcji do Pythona 
• Ustawienie Ref Count zwracanych obiektów 

10 

background image

Konwersja typów C->Python 

• PyObject *Py_BuildValue(char *format, ...) 

– Tworzy obiekt Pythona z listy zmiennych C na 

podstawie stringu określającego format (a’la 
printf()) 

– Typ PyObject jest uniwersalnym typem służącym 

do wymiany zmiennych/obiektów pomiędzy C i 
Pythonem 

 

11 

background image

Konwersja typów Python->C 

• int PyArg_ParseTuple(PyObject *args, char *format, ...) 

– Służy do konwersji zmiennych/obiektów Pythona do C 

na podstawie stringu określającego format (a’la 
scanf()) 

– PyObject *args jest obiektem interpretera Python 

zawierającym argumenty przekazane do funkcji 

• int PyArg_ParseTupleAndKeywords(PyObject *args, 

PyObject *kw, const char *format, char *keywords[], ...) 

– j.w. ale z opcją interpretacji argumentów nazwanych 

(keyword) do funkcji 

12 

background image

Tworzenie nowych 

zmiennych/obiektów Pythonowych 

Funkcja tworząca 
(zwraca obiekt typu PyObject* do Python/C) 

Wartośd Pythonowa 

Py_BuildValue("“) 

None 

Py_BuildValue("i", 123) 

123 

Py_BuildValue("iii", 123, 456, 789) 

(123, 456, 789) 

Py_BuildValue("s", "hello") 

'hello' 

Py_BuildValue("ss", "hello", "world") 

('hello', 'world') 

Py_BuildValue("s#", "hello", 4) 

‘hell’ 

Py_BuildValue("()")  

 () 

Py_BuildValue("(ii)", 123, 456) 

(123, 456) 

Py_BuildValue("[i,i]", 123, 456) 

[123, 456] 

Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) 

{'abc': 123, 'def': 456} 

Py_BuildValue("((ii)(ii)) (ii)", 1, 2, 3, 4, 5, 6) 

(((1, 2), (3, 4)), (5, 6)) 

13 

background image

Mechanizm zarządzenia pamięcią 

Python/C 

• Każdy obiekt/zmienna Pythona ma licznik odwołao (referencji) 

zwiększany przy każdym przypisaniu 

• Gdy licznik jest równy zero obiekt jest automatycznie usuwany z 

pamięci (tzw. Automatic Garbage Collection) 

• W kodzie C/C++ trzeba SAMEMU aktualizowad licznik! 
• Zwiększenie licznika:  

void Py_INCREF(PyObject *o) 

• Zmniejszanie licznika: 

void Py_DECREF(PyObject *o) 

• Zwracanie nowo utworzonego w C obiektu do Pythona: 

res = Py_BuildValue("i", 1234); 
Py_INCREF(res); 
return res; 

14 

background image

Reguły własności obiektów Python 

• Każde wywołanie Py_INCREF() powinno ostatecznie byd sparowane z 

wywołaniem Py_DECREF() 

• Py_INCREF() służy do „zabezpieczenia” życia obiektu na czas jego używania 

przez funkcję;  czasami korzysta się z „pożyczonych” referencji 

• Większośd (ALE NIE WSZYSTKIE!) funkcji Python/C API  wykonuje INCREF 

na zwracanych/tworzonych obiektach; w takim wypadku funkcja 

wywołująca jest odpowiedzialna za wykonanie Py_DECREF() 

• Nie ma konieczności INCREF dla każdej zmiennej lokalnej O ILE nie ma 

szansy, że w tym czasie ktoś inny wykona DECREF 

• Większośd funkcji zakłada, że przekazane argumenty (obiekty) są już 

„zabezpieczone”, więc nie wykonuje dla nich INCREF 

• WYJĄTKI:  

– PyTuple_SetItem() i PyList_SetItem() – przejmują z założenia argumenty 

„niezabezpieczone” 

– PyTuple_GetItem()  – nie wykonuje INCREF na zwracanych obiektach 
– i jeszcze inne – patrz dokumentacja!!!  

15 

background image

Obsługa i raportowanie błędów 

• Moduły rozszerzeo zwracają błąd do Pythona przez 

zwrot wartości NULL 

• Dodatkowo przed powrotem do interpretera funkcja C 

powinna ustawid typ błędu np.: 

– void PyErr_NoMemory() –  wyjątek typu MemoryError 
– void PyErr_SetFromErrno(PyObject *exc) – wyjątek z 

błędem ustalonym na podstawie wartości errno biblioteki 

CRT 

– void PyErr_SetObject(PyObject *exc, PyObject *val) – 

wyjątek typu exc wraz z obiektem obiekt/wartością 

wyjątku val 

– void PyErr_SetString(PyObject *exc, char *msg) – wyjątek 

typu exc wraz ze stringiem msg komunikatu błędu 
 

16 

background image

Szkielet modułu rozszerzającego 

#include <Python.h> 
 
static PyObject * spam_system(PyObject *self, PyObject *args)  

    const char *command; 
    int sts; 
    if (!PyArg_ParseTuple(args, "s", &command)) 
        return NULL; 
    sts = system(command); 
    return Py_BuildValue("i", sts); 

 
static PyMethodDef SpamMethods[] = { 
    {"system",  spam_system, METH_VARARGS, "Execute a shell command."}, 
    {NULL, NULL, 0, NULL}        /* Sentinel */ 
}; 
 
PyMODINIT_FUNC  
initspam(void)  

    (void) Py_InitModule("spam", SpamMethods); 

17 

background image

Konwencja C 

• Nazywanie modułów C – nazwą z 

podkreśleniem (np. _module.pyd/_module.so) 

• Obudowanie modułu C modułem Pythona: 

# module.py 
from _module import * 
# Dodatkowy kod wspierający poniżej… 
. . . 

18 

background image

Ręczna kompilacja modułu C 

• Niestety polecenia kompilacji są nieco różna 

dla różnych systemów operacyjnych 

– np. pod LINUX: 

> gcc -fpic -c -I/usr/local/include/python \ 
-I/usr/local/lib/python/config \ 
example.c wrapper.c 
> gcc -shared example.o wrapper.o -o 

examplemodule.so 

19 

background image

Kompilacja rozszerzeo za pomocą 

modułu distutils 

• Plik setup.py zawiera: pythonowy moduł obudowujący 

example.py oraz kod źródłowy C: pyexample.c, example.c: 

# setup.py 
from distutils.core import setup, Extension 
setup(name="example", 
  version="1.0", 
  py_modules = ['example.py'], 
  ext_modules = [ Extension("_example", 
   

 

["pyexample.c","example.c"]) ] 

  ) 

• Kompilacja modułu za pomocą polecenia: 

% python setup.py build 
% python setup.py install 

20 

background image

Generatory interfejsów 

• SWIG (Simplified Wrapper Interface Generator) – 

automatyczny generator wrapper’ów C/C++ dla 
języków dynamicznych Guile, Java, Mzscheme, Ocaml, 
Perl, Pike, PHP, Python, Ruby, and Tcl (

www.swig.org

). 

• SIP – generator interfejsów Python/C++; koncepcyjnie 

podobny do SWIG; używany do budowy interfejsów 
PyQt i PyKDE. 

• F2PY – generator interfejsów Fortran/C/Python; 

moduły C są generowane na podstawie plików sygnatur 
(.pyf) z kodu Fortran/C (

http://www.scipy.org/F2py

). 

21 

background image

Biblioteki Python/C/C++ 

• PyCXX – obiektowa biblioteka do budowy 

rozszerzeo do Pythona w C++ 
(

http://sourceforge.net/projects/cxx

) 

• Boost.Python – elegancka biblioteka obiektowa 

zapewniająca integrację klas, funkcji i obiektów 
C++ i Pythona (

www.boost.org

• ctypes – moduł Pythona umożliwia bezpośrednie 

wołanie funkcji w bibliotekach dynamicznych; 
zapewnia obsługę typów danych C oraz 
konwencję wywołao. 
 

22 

background image

Inne rozwiązania 

• Weave – element pakietu SciPy pozwala na 

umieszczanie kodu C/C++ bezpośrednio w kodzie 
Pythona w celu jego akceleracji 
(

http://www.scipy.org/Weave

• Pyrex – jest Pythonem z typami danych języka C 

(cdef); umożliwia kompilację takiego kodu do 
modułu C (coś jak Python2C) 

• Psyco – jest kompilatorem just-in-time (JIT) dla 

Pythona, co przyśpiesza wykonywanie 2-100x 
(typowo 4x) (

http://psyco.sourceforge.net

) 

 

23 

background image

SWIG 

• SWIG jest generatorem interfejsów do kodu 

C/C++ z języków skryptowych (Perl, Python, 
Ruby, Tcl, …).  

• Interfejsy są generowane na podstawie 

deklaracji w kodzie C/C++ (np. pliku 
nagłówkowego) lub pliku interfejsu 

• Szczegóły na 690 stronach dokumentacji  

24 

background image

SWIG – działanie 

25 

background image

SWIG – wykonanie 

26 

background image

SWIG – kod w C 

/* File : example.c */ 
#include <time.h> 
double My_variable = 3.0; 
  
int fact(int n) { 
 

if (n <= 1) return 1; 

 

else return n*fact(n-1); 


 
int my_mod(int x, int y) { 
 

return (x%y); 


 
char *get_time() 

 

time_t ltime; 

 

time(&ltime); 

 

return ctime(&ltime); 

http://www.swig.org/tutorial.html

 

27 

background image

SWIG – plik interfejsu 

/* example.i */ 
%module example 
%{ 
/* Put header files here or function declarations like 

below */ 

extern double My_variable; 
extern int fact(int n); 
extern int my_mod(int x, int y); 
extern char *get_time(); 
%} 
  
extern double My_variable; 
extern int fact(int n); 
extern int my_mod(int x, int y); 
extern char *get_time(); 

28 

background image

SWIG – kompilacja i uruchomienie 

% swig -python example.i 
% gcc -c example.c example_wrap.c \ 
        -I/usr/local/include/python2.1 
% ld -shared example.o example_wrap.o -o _example.so 
 
% python 
>>> import example 
>>> example.fact(5) 
120 
>>> example.my_mod(7,3) 

>>> example.get_time() 
'Sun Feb 11 23:01:07 1996‘ 

29 

background image

F2PY dla C – funkcja w C 

/* File foo.c */  
void foo(int n, double *x, double *y)  
{  
  int i;  
  for (i=0;i<n;i++) {  
   

y[i] = x[i] + i;  

  }  
}  

http://www.scipy.org/Cookbook/f2py_and_NumPy

  

30 

background image

F2PY dla C – plik sygnatury   

! File m.pyf 
python module m 
interface 
  subroutine foo(n,x,y) 
    intent(c) foo                 ! foo is a C function 
    intent(c)                     ! all foo arguments are  
                                  ! considered as C based 
    integer intent(hide), depend(x) :: n=len(x)  ! n is the length 
                                                 ! of input array x 
    double precision intent(in) :: x(n)          ! x is input array  
                                                 ! (or  arbitrary 

sequence) 

    double precision intent(out) :: y(n)         ! y is output array,  
                                                 ! see code in foo.c 
  end subroutine foo 
end interface 
end python module m 

31 

background image

F2PY dla C – plik setup.py 

# File setup.py 
def configuration(parent_package='',top_path=None): 
    from numpy.distutils.misc_util import 

Configuration 

    config = 

Configuration('',parent_package,top_path) 

 
    config.add_extension('m', 
                         sources = 

['m.pyf','foo.c']) 

    return config 
if __name__ == "__main__": 
    from numpy.distutils.core import setup 
    setup(**configuration(top_path='').todict()) 
 

32 

background image

F2PY dla C – kompilacja  

i uruchomienie 

• Kompilacja w wyniku której powstaje moduł C (m.so/m.pyd) : 

 
> f2py m.pyf foo.c -c 
 
>>> import m 
>>> print m.__doc__ 
This module 'm' is auto-generated with f2py (version:2_2130). 
Functions: 
  y = foo(x) 

>>> print m.foo.__doc__ 
foo - Function signature: 
  y = foo(x) 
Required arguments: 
  x : input rank-1 array('d') with bounds (n) 
Return objects: 
  y : rank-1 array('d') with bounds (n) 
>>> print m.foo([1,2,3,4,5])     
[ 1.  3.  5.  7.  9.] 

33 

background image

ctypes 

• Moduł Pythona umożliwia bezpośrednie 

wołanie funkcji w bibliotekach dynamicznych 

• Zapewnia obsługę typów danych C oraz 

konwencję wywołao. 

• Dokumentacja: 

– ctypes – A foreign function library for Python 

(dokumentacja Pythona) 

http://starship.python.net/crew/theller/ctypes/tu
torial.html

 

 

34 

background image

ctypes – typy danych I 

Typ ctypes 

Typ C 

Typ Python 

c_char

 

char 

1-character string 

c_wchar

 

wchar_t 

1-character unicode 
string 

c_byte

 

char 

int/long 

c_ubyte

 

unsigned char 

int/long 

c_short

 

short 

int/long 

c_ushort

 

unsigned short 

int/long 

c_int

 

int 

int/long 

c_uint

 

unsigned int 

int/long 

c_long

 

long 

int/long 

c_ulong

 

unsigned long 

int/long 

35 

background image

ctypes – typy danych II 

Typ ctypes 

Typ C 

Typ Python 

c_longlong

 

__int64 or long long 

int/long 

c_ulonglong

 

unsigned __int64 or unsigned long long 

int/long 

c_float

 

float 

float 

c_double

 

double 

float 

c_longdouble

 

long double 

float 

c_char_p

 

char * (NUL terminated) 

string or None 

c_wchar_p

 

wchar_t * (NUL terminated) 

unicode or None 

c_void_p

 

void * 

int/long or None 

36 

background image

ctypes – ładowanie biblioteki 

# WINDOWS 
>>> from ctypes import * 
>>> print windll.kernel32 
<WinDLL 'kernel32', handle ... at ...> 
>>> print cdll.msvcrt 
<CDLL 'msvcrt', handle ... at ...> 
>>> libc = cdll.msvcrt 
 
# LINUX 
>>> cdll.LoadLibrary("libc.so.6") 
<CDLL 'libc.so.6', handle ... at ...> 
>>> libc = CDLL("libc.so.6") 
>>> libc 
<CDLL 'libc.so.6', handle ... at ...> 

37 

background image

ctypes – wywołanie funkcji 

# EX1 
from ctypes import * 
libName = 'libc.so'  

# on a UNIX-based system 

libName = 'msvcrt.dll'  

# on Windows 

libc = CDLL(libName) 
libc.printf("Hello, World!\n") 
 
# EX2 
from ctypes import c_int, WINFUNCTYPE, windll  
from ctypes.wintypes import HWND, LPCSTR, UINT  
prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)  
paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, 

"caption", None), (1, "flags", 0)  

MessageBox = prototype(("MessageBoxA", windll.user32), 

paramflags) 

38 

background image

OSADZANIE PYTHONA 

39 

background image

Osadzanie – template 

#include <Python.h> 
 
int main(int argc, char **argv)  

  Py_Initialize(); 
  PyRun_SimpleString("print('Hello!')"); 
  Py_Finalize(); 
  return 0; 

40 

background image

Osadzanie – funkcje 

• Wykonanie z łaocucha znaków: 

Py_Initialize(); 
PyRun_SimpleString("i = 2"); 
PyRun_SimpleString("i = i*innprint i"); 
Py_Finalize(); 

• Wykonanie z pliku: 

Py_Initialize(); 
FILE * f = fopen("test.py", "r"); 
PyRun_SimpleFile(f, "test.py"); 
Py_Finalize(); 

41 

background image

Dostęp do Pythona z C 

• Importowanie modułów Pythona (emulacja 

polecenia import) 

• Dostęp do obiektów zdefiniowanych w modułach 
• Wywoływanie funkcji Python (funkcje w klasach, 

modułach) 

• Dostęp do zmiennych/atrybutów obiektów 
• Konwersja typów Python/C 
• Zarządzanie pamięcią 

42 

background image

Wywołanie funkcji w module 

PyObject *pName, *pModule, *pArgs, *pFunc, *pValue; 
 
# Import modułu Python 
Py_Initialize(); 
pName = PyString_FromString("mymod"); 
pModule = PyImport_Import(pName); 
 
# Pobranie funkcji z modułu 
pFunc = PyObject_GetAttrString(pModule, "foo"); 
 
# Wywołanie funkcji 
pValue = PyObject_CallObject(pFunc, pArgs); 

43