Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> Python

Python - Erweiterungsprogrammierung mit C

Vorherige SeiteNächste Seite

Jeder Code, den Sie in einer beliebigen kompilierten Sprache wie C, C++ oder Java schreiben, kann in ein anderes Python-Skript integriert oder importiert werden. Dieser Code wird als "Erweiterung" betrachtet.

Ein Python-Erweiterungsmodul ist nichts anderes als eine normale C-Bibliothek. Auf Unix-Rechnern enden diese Bibliotheken normalerweise auf .so (für gemeinsames Objekt). Auf Windows-Computern sehen Sie normalerweise .dll (für dynamisch verknüpfte Bibliotheken).

Voraussetzungen für das Schreiben von Erweiterungen

Um mit dem Schreiben Ihrer Erweiterung zu beginnen, benötigen Sie die Python-Header-Dateien.

Darüber hinaus wird davon ausgegangen, dass Sie über gute Kenntnisse in C oder C++ verfügen, um Python-Erweiterungen mithilfe der C-Programmierung zu schreiben.

Sehen Sie sich zuerst eine Python-Erweiterung an

Für Ihren ersten Blick auf ein Python-Erweiterungsmodul müssen Sie Ihren Code in vier Teile gruppieren −

Die Header-Datei Python.h

Sie müssen Python.h einschließen Header-Datei in Ihrer C-Quelldatei, die Ihnen Zugriff auf die interne Python-API gibt, die verwendet wird, um Ihr Modul in den Interpreter einzubinden.

Stellen Sie sicher, dass Sie Python.h vor allen anderen Headern einfügen, die Sie möglicherweise benötigen. Sie müssen den Includes mit den Funktionen folgen, die Sie von Python aufrufen möchten.

Die C-Funktionen

Die Signaturen der C-Implementierung Ihrer Funktionen nehmen immer eine der folgenden drei Formen an −

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

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

static PyObject *MyFunctionWithNoArgs( PyObject *self );

Jede der vorhergehenden Deklarationen gibt ein Python-Objekt zurück. Es gibt keine Leere Funktion in Python genauso wie in C. Wenn Sie nicht möchten, dass Ihre Funktionen einen Wert zurückgeben, geben Sie das C-Äquivalent von Pythons None zurück Wert. Die Python-Header definieren ein Makro, Py_RETURN_NONE, das dies für uns erledigt.

Die Namen Ihrer C-Funktionen können beliebig sein, da sie außerhalb des Erweiterungsmoduls nie zu sehen sind. Sie sind als statisch definiert Funktion.

Ihre C-Funktionen werden normalerweise benannt, indem die Python-Modul- und Funktionsnamen miteinander kombiniert werden, wie hier gezeigt −

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

Dies ist eine Python-Funktion namens func innerhalb des Moduls module . Sie werden Zeiger auf Ihre C-Funktionen in die Methodentabelle für das Modul einfügen, das normalerweise in Ihrem Quellcode als nächstes kommt.

Die Methodenzuordnungstabelle

Diese Methodentabelle ist ein einfaches Array von PyMethodDef-Strukturen. Diese Struktur sieht in etwa so aus −

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

Hier ist die Beschreibung der Mitglieder dieser Struktur −

Diese Tabelle muss mit einem Sentinel abgeschlossen werden, der aus NULL- und 0-Werten für die entsprechenden Elemente besteht.

Beispiel

Für die oben definierte Funktion haben wir folgende Methodenzuordnungstabelle −

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

Die Initialisierungsfunktion

Der letzte Teil Ihres Erweiterungsmoduls ist die Initialisierungsfunktion. Diese Funktion wird vom Python-Interpreter aufgerufen, wenn das Modul geladen wird. Es ist erforderlich, dass die Funktion initModule heißt , wobei Modul ist der Name des Moduls.

Die Initialisierungsfunktion muss aus der Bibliothek exportiert werden, die Sie erstellen werden. Die Python-Header definieren PyMODINIT_FUNC, um die entsprechenden Beschwörungsformeln für die jeweilige Umgebung, in der wir kompilieren, einzuschließen. Alles, was Sie tun müssen, ist es bei der Definition der Funktion zu verwenden.

Ihre C-Initialisierungsfunktion hat im Allgemeinen die folgende Gesamtstruktur −

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

Hier ist die Beschreibung von Py_InitModule3 Funktion −

Das alles zusammengenommen sieht wie folgt aus −

#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...");
}

Beispiel

Ein einfaches Beispiel, das alle oben genannten Konzepte nutzt −

#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 der Py_BuildValue -Funktion wird verwendet, um einen Python-Wert zu erstellen. Speichern Sie den obigen Code in der Datei hello.c. Wir würden sehen, wie dieses Modul kompiliert und installiert wird, damit es vom Python-Skript aufgerufen wird.

Erweiterungen erstellen und installieren

Die distutils -Paket macht es sehr einfach, Python-Module, sowohl reine Python- als auch Erweiterungsmodule, auf standardmäßige Weise zu verteilen. Module werden in Quellform verteilt und über ein Setup-Skript namens setup.py erstellt und installiert wie folgt.

Für das obige Modul müssen Sie das folgende setup.py-Skript vorbereiten −

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

Verwenden Sie nun den folgenden Befehl, der alle erforderlichen Kompilierungs- und Verknüpfungsschritte mit den richtigen Compiler- und Linker-Befehlen und -Flags durchführt, und kopieren Sie die resultierende dynamische Bibliothek in ein geeignetes Verzeichnis −

$ python setup.py install

Auf Unix-basierten Systemen müssen Sie diesen Befehl höchstwahrscheinlich als root ausführen, um Berechtigungen zum Schreiben in das Verzeichnis site-packages zu erhalten. Unter Windows ist dies normalerweise kein Problem.

Erweiterungen importieren

Sobald Sie Ihre Erweiterung installiert haben, können Sie diese Erweiterung wie folgt in Ihr Python-Skript importieren und aufrufen −

#!/usr/bin/python
import helloworld

print helloworld.helloworld()

Dies würde zu folgendem Ergebnis führen −

Hello, Python extensions!!

Funktionsparameter übergeben

Da Sie höchstwahrscheinlich Funktionen definieren wollen, die Argumente akzeptieren, können Sie eine der anderen Signaturen für Ihre C-Funktionen verwenden. Beispielsweise würde die folgende Funktion, die eine Reihe von Parametern akzeptiert, wie folgt definiert:−

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

Die Methodentabelle, die einen Eintrag für die neue Funktion enthält, würde wie folgt aussehen −

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

Sie können die API PyArg_ParseTuple verwenden Funktion, um die Argumente aus dem einen PyObject-Zeiger zu extrahieren, der an Ihre C-Funktion übergeben wird.

Das erste Argument für PyArg_ParseTuple ist das Argument args. Dies ist das Objekt, das Sie parsen werden . Das zweite Argument ist eine Formatzeichenfolge, die die Argumente so beschreibt, wie Sie sie erwarten. Jedes Argument wird wie folgt durch ein oder mehrere Zeichen in der Formatzeichenfolge dargestellt.

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;
}

Wenn Sie die neue Version Ihres Moduls kompilieren und importieren, können Sie die neue Funktion mit einer beliebigen Anzahl von Argumenten beliebigen Typs aufrufen −

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)

Wahrscheinlich fallen Ihnen noch mehr Variationen ein.

Das PyArg_ParseTuple Funktion

Hier ist die Standardsignatur für PyArg_ParseTuple Funktion −

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

Diese Funktion gibt 0 für Fehler und einen Wert ungleich 0 für Erfolg zurück. Tupel ist das PyObject*, das das zweite Argument der C-Funktion war. Hier formatieren ist ein C-String, der obligatorische und optionale Argumente beschreibt.

Hier ist eine Liste von Formatcodes für PyArg_ParseTuple Funktion −

Code C-Typ Bedeutung
c Zeichen Ein Python-String der Länge 1 wird zu einem C-Zeichen.
d doppelt Ein Python-Float wird zu einem C-Double.
f schweben Ein Python-Float wird zu einem C-Float.
ich int Ein Python-Int wird zu einem C-Int.
l lang Ein Python int wird zu einem C long.
L lang lang Ein Python int wird zu einem C long long
O PyObject* Ruft eine geliehene Nicht-NULL-Referenz auf das Python-Argument ab.
s Zeichen* Python-String ohne eingebettete Nullen in C-Zeichen*.
s# char*+int Jeder Python-String an C-Adresse und Länge.
t# char*+int Schreibgeschützter Einzelsegmentpuffer an C-Adresse und Länge.
u Py_UNICODE* Python Unicode ohne eingebettete Nullen zu C.
u# Py_UNICODE*+int Beliebige Python-Unicode-C-Adresse und Länge.
w# char*+int Lesen/Schreiben des Einzelsegmentpuffers an C-Adresse und Länge.
z Zeichen* Akzeptiert wie s auch None (setzt C char* auf NULL).
z# char*+int Akzeptiert wie s# auch None (setzt C char* auf NULL).
(...) gemäß ... Eine Python-Sequenz wird als ein Argument pro Element behandelt.
| Die folgenden Argumente sind optional.
: Formatende, gefolgt von Funktionsname für Fehlermeldungen.
; Ende formatieren, gefolgt vom gesamten Text der Fehlermeldung.

Rückgabewerte

Py_BuildValue nimmt einen Formatstring ähnlich wie PyArg_ParseTuple an tut. Anstatt die Adressen der Werte, die Sie erstellen, zu übergeben, übergeben Sie die tatsächlichen Werte. Hier ist ein Beispiel, das zeigt, wie man eine add-Funktion implementiert −

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);
}

So würde es aussehen, wenn es in Python implementiert wäre −

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

Sie können zwei Werte von Ihrer Funktion wie folgt zurückgeben, dies würde mit einer Liste in Python erfasst werden.

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);
}

So würde es aussehen, wenn es in Python implementiert wäre −

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

Der Py_BuildValue Funktion

Hier ist die Standardsignatur für Py_BuildValue Funktion −

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

Hier formatieren ist ein C-String, der das zu erstellende Python-Objekt beschreibt. Die folgenden Argumente von Py_BuildValue sind C-Werte, aus denen das Ergebnis aufgebaut wird. Das PyObject* Ergebnis ist eine neue Referenz.

Die folgende Tabelle listet die häufig verwendeten Code-Strings auf, von denen null oder mehr zu einem String-Format verbunden sind.

Code C-Typ Bedeutung
c Zeichen Ein C-Zeichen wird zu einem Python-String der Länge 1.
d doppelt Ein C-Double wird zu einem Python-Float.
f schweben Ein C-Float wird zu einem Python-Float.
ich int Ein C-int wird zu einem Python-int.
l lang Ein C long wird zu einem Python int.
N PyObject* Übergibt ein Python-Objekt und stiehlt eine Referenz.
O PyObject* Übergibt ein Python-Objekt und INCREFs wie gewohnt.
O& umwandeln+aufheben* Beliebige Umwandlung
s Zeichen* C 0-terminiertes char* zu Python-String oder NULL zu None.
s# char*+int C char* und Länge zu Python-String oder NULL zu None.
u Py_UNICODE* C-weite, nullterminierte Zeichenfolge zu Python Unicode oder NULL zu None.
u# Py_UNICODE*+int C-breiter String und Länge zu Python Unicode oder NULL zu None.
w# char*+int Lesen/Schreiben des Einzelsegmentpuffers an C-Adresse und Länge.
z Zeichen* Akzeptiert wie s auch None (setzt C char* auf NULL).
z# char*+int Akzeptiert wie s# auch None (setzt C char* auf NULL).
(...) gemäß ... Erzeugt Python-Tupel aus C-Werten.
[...] gemäß ... Erstellt eine Python-Liste aus C-Werten.
{...} gemäß ... Erzeugt ein Python-Wörterbuch aus C-Werten, abwechselnd Schlüsseln und Werten.

Code {...} erstellt Wörterbücher aus einer geraden Anzahl von C-Werten, abwechselnd Schlüsseln und Werten. Beispielsweise gibt Py_BuildValue("{issi}",23,"zig","zag",42) ein Wörterbuch wie {23:'zig','zag':42} von Python zurück.


Python

  1. Python objektorientierte Programmierung
  2. Python Print()-Anweisung:Drucken mit Beispielen
  3. Python String strip() Funktion mit BEISPIEL
  4. Python String count() mit BEISPIELE
  5. Python String format() Erklären Sie mit BEISPIELE
  6. Python String find() Methode mit Beispielen
  7. Python-Lambda-Funktionen mit BEISPIELE
  8. Python-Funktion round() mit BEISPIELE
  9. Python map() Funktion mit BEISPIELE
  10. Python Timeit() mit Beispielen