Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Industrial programming >> Python

Python - Extensie programmeren met C

Vorige paginaVolgende pagina

Elke code die u schrijft met behulp van een gecompileerde taal zoals C, C++ of Java, kan worden geïntegreerd of geïmporteerd in een ander Python-script. Deze code wordt beschouwd als een "extensie".

Een Python-uitbreidingsmodule is niets meer dan een normale C-bibliotheek. Op Unix-machines eindigen deze bibliotheken meestal op .so (voor gedeeld object). Op Windows-machines ziet u meestal .dll (voor dynamisch gekoppelde bibliotheek).

Vereisten voor het schrijven van extensies

Om te beginnen met het schrijven van je extensie, heb je de Python-headerbestanden nodig.

  • Op Unix-machines moet hiervoor meestal een ontwikkelaarspecifiek pakket worden geïnstalleerd, zoals python2.5-dev.

  • Windows-gebruikers krijgen deze headers als onderdeel van het pakket wanneer ze het binaire Python-installatieprogramma gebruiken.

Bovendien wordt aangenomen dat je een goede kennis hebt van C of C++ om een ​​Python-extensie te schrijven met C-programmering.

Eerst kijken naar een Python-extensie

Voor uw eerste blik op een Python-uitbreidingsmodule, moet u uw code in vier delen groeperen −

  • Het headerbestand Python.h .

  • De C-functies die u wilt weergeven als de interface van uw module.

  • Een tabel die de namen van je functies in kaart brengt zoals Python-ontwikkelaars ze zien aan C-functies in de uitbreidingsmodule.

  • Een initialisatiefunctie.

Het kopbestand Python.h

U moet Python.h . opnemen header-bestand in uw C-bronbestand, dat u toegang geeft tot de interne Python API die wordt gebruikt om uw module in de interpreter te haken.

Zorg ervoor dat u Python.h opneemt vóór andere headers die u mogelijk nodig hebt. Je moet de include volgen met de functies die je wilt aanroepen vanuit Python.

De C-functies

De handtekeningen van de C-implementatie van uw functies nemen altijd een van de volgende drie vormen aan −

static PyObject *MyFunction( PyObject *self, PyObject *args );

static PyObject *MyFunctionWithKeywords(PyObject *self,
                                 PyObject *args,
                                 PyObject *kw);

static PyObject *MyFunctionWithNoArgs( PyObject *self );

Elk van de voorgaande declaraties retourneert een Python-object. Er bestaat niet zoiets als een leegte functie in Python zoals er is in C. Als u niet wilt dat uw functies een waarde retourneren, retourneert u het C-equivalent van Python's Geen waarde. De Python-headers definiëren een macro, Py_RETURN_NONE, die dit voor ons doet.

De namen van uw C-functies kunnen zijn wat u maar wilt, aangezien ze nooit buiten de uitbreidingsmodule worden gezien. Ze zijn gedefinieerd als statisch functie.

Uw C-functies worden meestal benoemd door de Python-module en functienamen samen te combineren, zoals hier getoond −

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

Dit is een Python-functie genaamd func binnenkant van de module module . Je plaatst verwijzingen naar je C-functies in de methodetabel voor de module die meestal de volgende is in je broncode.

De methodetoewijzingstabel

Deze methodetabel is een eenvoudige reeks PyMethodDef-structuren. Die structuur ziet er ongeveer zo uit −

struct PyMethodDef {
   char *ml_name;
   PyCFunction ml_meth;
   int ml_flags;
   char *ml_doc;
};

Hier is de beschrijving van de leden van deze structuur −

  • ml_name − Dit is de naam van de functie zoals de Python-interpreter deze presenteert wanneer deze wordt gebruikt in Python-programma's.

  • ml_meth − Dit moet het adres zijn van een functie die een van de handtekeningen heeft die in de vorige paragraaf zijn beschreven.

  • ml_flags − Dit vertelt de interpreter welke van de drie handtekeningen ml_meth gebruikt.

    • Deze vlag heeft meestal een waarde van METH_VARARGS.

    • Deze vlag kan bitsgewijze OR'ed worden met METH_KEYWORDS als u trefwoordargumenten in uw functie wilt toestaan.

    • Dit kan ook de waarde METH_NOARGS hebben die aangeeft dat u geen argumenten wilt accepteren.

  • ml_doc − Dit is de docstring voor de functie, die NULL kan zijn als je geen zin hebt om er een te schrijven.

Deze tabel moet worden afgesloten met een schildwacht die bestaat uit NULL- en 0-waarden voor de juiste leden.

Voorbeeld

Voor de hierboven gedefinieerde functie hebben we de volgende methodetoewijzingstabel −

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

De initialisatiefunctie

Het laatste onderdeel van uw uitbreidingsmodule is de initialisatiefunctie. Deze functie wordt aangeroepen door de Python-interpreter wanneer de module wordt geladen. De functie moet de naam initModule . hebben , waarbij Module is de naam van de module.

De initialisatiefunctie moet worden geëxporteerd vanuit de bibliotheek die u gaat bouwen. De Python-headers definiëren PyMODINIT_FUNC om de juiste bezweringen op te nemen om dat te laten gebeuren voor de specifieke omgeving waarin we compileren. Het enige wat u hoeft te doen is het te gebruiken bij het definiëren van de functie.

Uw C-initialisatiefunctie heeft over het algemeen de volgende algemene structuur −

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

Hier is de beschrijving van Py_InitModule3 functie −

  • leuk − Dit is de functie die moet worden geëxporteerd.

  • module _methoden − Dit is de naam van de toewijzingstabel die hierboven is gedefinieerd.

  • docstring − Dit is de opmerking die u in uw extensie wilt geven.

Als je dit allemaal samenvoegt, ziet het er als volgt uit −

#include <Python.h>

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

Voorbeeld

Een eenvoudig voorbeeld dat gebruik maakt van alle bovenstaande concepten −

#include <Python.h>

static PyObject* helloworld(PyObject* self) {
   return Py_BuildValue("s", "Hello, Python extensions!!");
}

static char helloworld_docs[] =
   "helloworld( ): Any message you want to put here!!\n";

static PyMethodDef helloworld_funcs[] = {
   {"helloworld", (PyCFunction)helloworld, 
      METH_NOARGS, helloworld_docs},
      {NULL}
};

void inithelloworld(void) {
   Py_InitModule3("helloworld", helloworld_funcs,
                  "Extension module example!");
}

Hier de Py_BuildValue functie wordt gebruikt om een ​​Python-waarde te bouwen. Bewaar bovenstaande code in hello.c bestand. We zouden zien hoe we deze module kunnen compileren en installeren om te worden aangeroepen vanuit het Python-script.

Extensies bouwen en installeren

De distutils pakket maakt het zeer eenvoudig om Python-modules, zowel pure Python- als uitbreidingsmodules, op een standaard manier te distribueren. Modules worden gedistribueerd in bronvorm en gebouwd en geïnstalleerd via een installatiescript dat gewoonlijk setup.py wordt genoemd als volgt.

Voor de bovenstaande module moet u het volgende setup.py-script voorbereiden −

from distutils.core import setup, Extension
setup(name='helloworld', version='1.0',  \
      ext_modules=[Extension('helloworld', ['hello.c'])])

Gebruik nu de volgende opdracht, die alle benodigde compilatie- en koppelingsstappen uitvoert, met de juiste compiler- en linkeropdrachten en vlaggen, en kopieert de resulterende dynamische bibliotheek naar een geschikte map −

$ python setup.py install

Op Unix-gebaseerde systemen moet u deze opdracht waarschijnlijk als root uitvoeren om machtigingen te hebben om naar de map site-packages te schrijven. Dit is meestal geen probleem op Windows.

Extensies importeren

Nadat u uw extensie hebt geïnstalleerd, kunt u die extensie als volgt importeren en aanroepen in uw Python-script −

#!/usr/bin/python
import helloworld

print helloworld.helloworld()

Dit zou het volgende resultaat opleveren −

Hello, Python extensions!!

Functieparameters doorgeven

Aangezien u hoogstwaarschijnlijk functies wilt definiëren die argumenten accepteren, kunt u een van de andere handtekeningen voor uw C-functies gebruiken. De volgende functie, die een aantal parameters accepteert, zou bijvoorbeeld als volgt worden gedefinieerd −

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Parse args and do something interesting here. */
   Py_RETURN_NONE;
}

De methodetabel die een invoer voor de nieuwe functie bevat, ziet er als volgt uit −

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { "func", module_func, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
};

U kunt API PyArg_ParseTuple . gebruiken functie om de argumenten te extraheren uit de ene PyObject-aanwijzer die is doorgegeven aan uw C-functie.

Het eerste argument voor PyArg_ParseTuple is het argument args. Dit is het object dat u gaat parseren . Het tweede argument is een opmaakreeks die de argumenten beschrijft zoals u verwacht dat ze verschijnen. Elk argument wordt als volgt weergegeven door een of meer tekens in de opmaakreeks.

static PyObject *module_func(PyObject *self, PyObject *args) {
   int i;
   double d;
   char *s;

   if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {
      return NULL;
   }
   
   /* Do something interesting here. */
   Py_RETURN_NONE;
}

Door de nieuwe versie van uw module te compileren en te importeren, kunt u de nieuwe functie aanroepen met een willekeurig aantal argumenten van elk type −

module.func(1, s="three", d=2.0)
module.func(i=1, d=2.0, s="three")
module.func(s="three", d=2.0, i=1)

Je kunt waarschijnlijk nog meer variaties bedenken.

De PyArg_ParseTuple Functie

Hier is de standaard handtekening voor PyArg_ParseTuple functie −

int PyArg_ParseTuple(PyObject* tuple,char* format,...)

Deze functie retourneert 0 voor fouten en een waarde die niet gelijk is aan 0 voor succes. tuple is het PyObject* dat het tweede argument van de C-functie was. Hier opmaak is een C-tekenreeks die verplichte en optionele argumenten beschrijft.

Hier is een lijst met opmaakcodes voor PyArg_ParseTuple functie −

Code C-type Betekenis
c char Een Python-tekenreeks met lengte 1 wordt een C-teken.
d dubbel Een Python-float wordt een C-double.
f drijvend Een Python-float wordt een C-float.
ik int Een Python int wordt een C int.
l lang Een Python int wordt een C lang.
L lang lang Een Python int wordt een C lang lang
O PyObject* Krijgt een niet-NULL geleende verwijzing naar het Python-argument.
s char* Python string zonder ingesloten nulls naar C char*.
s# char*+int Elke Python-string naar C-adres en lengte.
t# char*+int Alleen-lezen buffer met één segment naar C-adres en lengte.
u Py_UNICODE* Python Unicode zonder ingesloten nulls naar C.
u# Py_UNICODE*+int Elk Python Unicode C-adres en lengte.
w# char*+int Lees/schrijf enkel-segment buffer naar C adres en lengte.
z char* Like s, accepteert ook Geen (zet C char* op NULL).
z# char*+int Net als s#, accepteert ook Geen (zet C char* op NULL).
(...) volgens ... Een Python-reeks wordt behandeld als één argument per item.
| De volgende argumenten zijn optioneel.
: Formaat einde, gevolgd door functienaam voor foutmeldingen.
; Formaat einde, gevolgd door de volledige tekst van het foutbericht.

Waarden retourneren

Py_BuildValue neemt een formaattekenreeks in zoals PyArg_ParseTuple doet. In plaats van de adressen door te geven van de waarden die u aan het bouwen bent, geeft u de werkelijke waarden door. Hier is een voorbeeld dat laat zien hoe je een add-functie implementeert −

static PyObject *foo_add(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("i", a + b);
}

Dit is hoe het eruit zou zien als het geïmplementeerd was in Python −

def add(a, b):
   return (a + b)

U kunt als volgt twee waarden uit uw functie retourneren, dit zou worden vastgelegd met behulp van een lijst in Python.

static PyObject *foo_add_subtract(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("ii", a + b, a - b);
}

Dit is hoe het eruit zou zien als het geïmplementeerd was in Python −

def add_subtract(a, b):
   return (a + b, a - b)

De Py_BuildValue Functie

Hier is de standaard handtekening voor Py_BuildValue functie −

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

Hier opmaak is een C-tekenreeks die het te bouwen Python-object beschrijft. De volgende argumenten van Py_BuildValue zijn C-waarden waaruit het resultaat is opgebouwd. Het PyObject* resultaat is een nieuwe referentie.

De volgende tabel geeft een overzicht van de veelgebruikte codereeksen, waarvan nul of meer worden samengevoegd in tekenreeksindeling.

Code C-type Betekenis
c char Een C-teken wordt een Python-tekenreeks met lengte 1.
d dubbel Een C-double wordt een Python-float.
f drijvend Een C-float wordt een Python-float.
ik int Een C int wordt een Python int.
l lang Een C long wordt een Python int.
N PyObject* Geeft een Python-object door en steelt een referentie.
O PyObject* Geeft een Python-object door en INCREFs het zoals normaal.
O& convert+void* Willekeurige conversie
s char* C 0-terminated char* naar Python string, of NULL naar None.
s# char*+int C char* en lengte naar Python-tekenreeks, of NULL naar Geen.
u Py_UNICODE* C-brede, null-terminated string naar Python Unicode, of NULL naar None.
u# Py_UNICODE*+int C-brede string en lengte naar Python Unicode, of NULL naar Geen.
w# char*+int Lees/schrijf enkel-segment buffer naar C adres en lengte.
z char* Like s, accepteert ook Geen (zet C char* op NULL).
z# char*+int Net als s#, accepteert ook Geen (zet C char* op NULL).
(...) volgens ... Bouwt Python-tuple van C-waarden.
[...] volgens ... Bouwt een Python-lijst op van C-waarden.
{...} volgens ... Bouwt Python-woordenboek op basis van C-waarden, afwisselende sleutels en waarden.

Code {...} bouwt woordenboeken op van een even aantal C-waarden, afwisselend sleutels en waarden. Py_BuildValue("{issi}",23,"zig","zag",42) retourneert bijvoorbeeld een woordenboek zoals {23:'zig','zag':42} van Python.


Python

  1. Objectgeoriënteerd programmeren in Python
  2. Python Print()-instructie:afdrukken met voorbeelden
  3. Python String strip() Functie met VOORBEELD
  4. Python String count() met VOORBEELDEN
  5. Python String format() Leg uit met VOORBEELDEN
  6. Methode Python String find() met voorbeelden
  7. Python Lambda-functies met VOORBEELDEN
  8. Python round() functie met VOORBEELDEN
  9. Python map() functie met VOORBEELDEN
  10. Python Timeit() met voorbeelden
  11. Python-teller in verzamelingen met voorbeeld