Hlavní navigace

Vytváříme v C/C++ modul pro Python

Michal Hořejšek 3. 11. 2009

Programovací jazyk Python má velké plus, že složité věci v něm můžete napsat opravdu jednoduše a tím urychlit vývoj. Naopak velkým nedostatkem je výkon tohoto jazyka. U malých projektů to sice nepocítíte, ale u větších, kde se často něco počítá, to je horší. Jak pro Python vytvořit modul v C/C++?

Python je velmi oblíbený jazyk hlavně díky jeho jednoduchosti, tedy díky tomu, že je interpretovaný. Proto můžeme složité věci psát jednoduše a místo několika řádků v C/C++ napsat jen jeden a máme vystaráno – je to dobré pro čitelnost. Dále je to výborné kvůli přenositelnosti – nemusíme totiž zdrojový kód kompilovat do strojového kódu pro každou architekturu a stačí jen spustit zdrojový kód a nechat zpracovávat instrukci za instrukcí.

python logo

Chcete o Pythonu vědět více?

Pokud se chcete o programovacím jazyce Python dozvědět více, určitě nesmíte vynechat náš seriál Létající cirkus, kde se v jednadvaceti článcích dozvíte o vývoji v Pythonu to nejdůležitější.

Z tohoto důvodu je zároveň ale Python pomalejší a výrazně se to projeví na opravdu náročných výpočtech (sám o sobě je Python rychlík ve srovnání s jinými interpretovanými jazyky, zvlášť když umíme Python správně využít). Pro eliminaci této nevýhody můžeme využít možnost vyrábět pro Python v jazyku C nebo C++ (existuje i implementace v jazyce Java).

C/C++ kód

Ukážeme si jednoduchou ukázku, jak si vyrobit v C/C++ malou kalkulačku, která bude umět sčítání a odčítání a kterou budeme používat v Pythonu.

#include <Python.h>

PyDoc_STRVAR( calc__doc__, "calc" );
PyDoc_STRVAR( plus__doc__, "plus(x,y)" );
PyDoc_STRVAR( minus__doc__, "minus(x,y)" );

static PyObject * py_plus( PyObject *self, PyObject *args )
{
  int x=0, y=0;
  if ( !PyArg_ParseTuple( args, "ii", &x, &y ) )
    return NULL;
  return PyInt_FromLong( ( long ) x+y );
}

static PyObject * py_minus( PyObject *self, PyObject *args )
{
  int x=0, y=0;
  if ( !PyArg_ParseTuple( args, "ii", &x, &y ) )
    return NULL;
  return PyInt_FromLong( ( long ) x-y );
}

static PyMethodDef calc_methods[] = {
  { "plus",  py_plus, METH_VARARGS, plus__doc__ },
  { "minus",  py_minus, METH_VARARGS, minus__doc__ },
  { NULL, NULL }
};

PyMODINIT_FUNC initcalc( void )
{
  Py_InitModule3( "calc", calc_methods, calc__doc__ );
}

Nejprve si na prvním nainkludujeme potřebný hlavičkový soubor, abychom mohli modul pro Python vytvořit.

Na třetím až pátým řádku si nadefinujeme dokumentační proměnné pro náš modul i funkce. Tyto řetězce budou poté přístupné klasicky v Pythonu pod proměnnou __doc__. (Můžeme si nechat zobrazit instrukcí  print calc.__doc__).

Poté následují samotné funkce modulu. Na sedmém řádku je, jak má vypadat, hlavička funkce, která se bude volat z Pythonu. Pokud se ptáte, co to je PyObject, tak je to univerzální pythoní datový typ pro cokoli. Pro každou funkci budeme mít vždy připraveny dva argumenty. První argument je self určuje objekt, který voláme (v našem případě to bude vždy Null) a druhý argument args předává funkci v C/C++ všechny předávané argumenty z Pythonu.

V obou funkcích budeme pracovat s dvěmi celými čísly, a proto si v obou funkcích nejprve nadefinujeme dvě proměnné typu integer. Tyto proměnné následně naplníme předávanými čísly z Pythonu pomocí PyArg_ParseTuple. Tato funkce nám nejen „vytáhne“ čísla, ale zabrání nesprávnému použití (například špatný datový typ, či jiný počet argumentů), proto funkci používám v podmínce a v případě selhání vrátím NULL (pokud se ptáte proč NULL a ne Py_None, který reprezentuje pythoní None, tak je to proto, že chceme, aby se vyvolala výjimka a oznámila chybu). Pokud vše dobře dopadne, tak nakonec vrátím pythoní datový typ integer pomocí funkce PyInt_FromLong (všimněte si, že jsem při výpočtu přetypoval výsledek na  long integer).

Sice máme funkce napsané, ale v Pythonu ještě nebudou přístupné, protože nejsou namapovány. Takže po funkcích py_plus a py_minus následuje inicializace pole s funkcemi, které budou v Pythonu přístupné. V poli jsou pole, která na první položce definují název funkce v Pythonu; na další položce název funkce v C/C++; na třetí položce nalezneme METH_VARARGS, což určuje, že funkce nemá klíčové položky; a nakonec, na posledním místě je dokumentace k funkci – použité proměnné jsme si deklarovali už na začátku a můžeme klidně psát komentáře přímo sem. Jako na posledním místě musí být zarážka, která určuje konec a je to pouze pole složené z dvou položek, které jsou obě nastaveny na  NULL.

Úplně nakonec napíšeme inicializační funkci, která se provede po načtení modulu. V této rutině pouze inicializujeme modul funkcí Py_InitModule3 a sdělíme název modulu, mapování funkcí a dokumentaci k modulu.

Kompilace modulu

Tímto máme zdrojový kód našeho modulu a potřebujeme ho zkompilovat. Snad nejjednodušší cesta je pomocí Pythonu.

from distutils.core import setup, Extension
setup( name="calc", version="0.0", ext_modules = [ Extension( "calc", ["calc.c"] ) ] )

Nejprve jsme si importovali potřebné metody a poté jen zavolali metodu setup, která se o celou kompilaci postará. Nastaví jméno a verzi modulu (lze nastavit více věcí, podívejte se do dokuemtace). Argument ext_modules nastaví vstupní C/C++ soubor a výstupní název modulu.

Po zavolání tohoto pythoního skriptu se nám modul v C/C++ zkompiluje a nalezneme modul přibližně ve složce ""./build/lib.linux-x86_64–2.6"" (já mám 64bit systém, proto x86_64, proto se název složky může mírně měnit), kde je soubor ""calc.so"". Tento soubor je náš modul a přidáme si ho do složky našeho projektu.

Využívání modulu

Využívat modul je už hračkou. Stačí, pokud zkusíme zavolat postupně tyto instrukce:

>>> import calc
>>> calc.__doc__
'calc'
>>> calc.plus( 5, 2 )
7
>>> calc.minus.__doc__
'minus(x,y)'
>>> calc.minus( 5, 3 )
2

Závěr

Takto jednoduché je napsat vlastní jednoduchý modul v C/C++ pro Python a další informace můžete nalézt například v dokumentaci. Někdy příště se podíváme na nějaké specialitky při vytváření modulů pro Python.

Našli jste v článku chybu?

21. 1. 2010 18:24

Pokud mate na mysli graficky vektorovy editor Inkscape, tak ten je psan v c++ (gtkmm).

Co se ale python bindingu tyce, tak ten se v praxi dela ze dvou pripadu:
- dotycna uloha(fce) by byla opravdu v pythonu pomala, nebo spatne programovatelna
- mame jiz hotovou komponentu, a chceme ji dostat do pythonu



8. 11. 2009 20:20

Ondrej Certik (neregistrovaný)

Myslim ze jedna z nejlepsich moznosti je pouzit cython (cython.org). Umi udelat wrappery na C i C++, ale pritom to vygeneruje jednoduchy C soubor, takze je do toho videt, co se tam deje. Krome toho lze cython pouzit i primo, na urychleni kriticke casti kodu (v pythonu).

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Lupa.cz: Levný tarif pro Brno nebude. Radní: je to kartel

Levný tarif pro Brno nebude. Radní: je to kartel

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

Root.cz: Vypadl Google a rozbilo se toho hodně

Vypadl Google a rozbilo se toho hodně

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Vitalia.cz: Říká amoleta - a myslí palačinka

Říká amoleta - a myslí palačinka

DigiZone.cz: Flix TV má set-top box s HEVC

Flix TV má set-top box s HEVC

DigiZone.cz: ČRa DVB-T2 ověřeno: Hisense a Sencor

ČRa DVB-T2 ověřeno: Hisense a Sencor

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Vitalia.cz: To není kašel! Správná diagnóza zachrání život

To není kašel! Správná diagnóza zachrání život

Vitalia.cz: Znáte „černý detox“? Ani to nezkoušejte

Znáte „černý detox“? Ani to nezkoušejte

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

Podnikatel.cz: Zavře krám u #EET Malá pokladna a Teeta?

Zavře krám u #EET Malá pokladna a Teeta?

120na80.cz: Horní cesty dýchací. Zkuste fytofarmaka

Horní cesty dýchací. Zkuste fytofarmaka

Lupa.cz: Insolvenční řízení kvůli cookies? Vítejte v ČR

Insolvenční řízení kvůli cookies? Vítejte v ČR

Vitalia.cz: Dáte si jahody s plísní?

Dáte si jahody s plísní?

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?