Einleitung¶
Die Application Programmer’s Interface (API) zu Python bietet C- und C++-Programmierern Zugriff auf den Python-Interpreter auf verschiedenen Ebenen. Die API ist gleichermaßen aus C++ nutzbar, wird aber zur Kürze im Allgemeinen als Python/C-API bezeichnet. Es gibt zwei grundlegend unterschiedliche Gründe für die Verwendung der Python/C-API. Der erste Grund ist das Schreiben von Erweiterungsmodulen für spezielle Zwecke; dies sind C-Module, die den Python-Interpreter erweitern. Dies ist wahrscheinlich die häufigste Verwendung. Der zweite Grund ist die Verwendung von Python als Komponente in einer größeren Anwendung; diese Technik wird im Allgemeinen als Einbetten von Python in eine Anwendung bezeichnet.
Das Schreiben eines Erweiterungsmoduls ist ein relativ gut verstandener Prozess, bei dem ein „Kochbuch“-Ansatz gut funktioniert. Es gibt mehrere Werkzeuge, die den Prozess bis zu einem gewissen Grad automatisieren. Während Menschen Python seit seiner frühen Existenz in andere Anwendungen eingebettet haben, ist der Prozess des Einbettens von Python nicht so geradlinig wie das Schreiben einer Erweiterung.
Viele API-Funktionen sind unabhängig davon nützlich, ob Sie Python einbetten oder erweitern; außerdem werden die meisten Anwendungen, die Python einbetten, auch ein benutzerdefiniertes Erweiterungsmodul benötigen. Daher ist es wahrscheinlich eine gute Idee, sich mit dem Schreiben einer Erweiterung vertraut zu machen, bevor Sie versuchen, Python in eine reale Anwendung einzubetten.
Sprachversionskompatibilität¶
Die C-API von Python ist kompatibel mit den C11- und C++11-Versionen von C und C++.
Dies ist eine untere Grenze: Die C-API erfordert keine Funktionen aus späteren C/C++-Versionen. Sie müssen den „c11-Modus“ Ihres Compilers nicht aktivieren.
Codierungsstandards¶
Wenn Sie C-Code für die Aufnahme in CPython schreiben, müssen Sie unbedingt die in PEP 7 definierten Richtlinien und Standards befolgen. Diese Richtlinien gelten unabhängig von der Python-Version, zu der Sie beitragen. Das Befolgen dieser Konventionen ist für Ihre eigenen Drittanbieter-Erweiterungsmodule nicht notwendig, es sei denn, Sie beabsichtigen, sie schließlich zu Python beizutragen.
Include-Dateien¶
Alle Funktions-, Typ- und Makrodefinitionen, die für die Verwendung der Python/C-API benötigt werden, sind durch die folgende Zeile in Ihrem Code enthalten
#define PY_SSIZE_T_CLEAN
#include <Python.h>
Dies impliziert die Einbeziehung der folgenden Standard-Header: <stdio.h>, <string.h>, <errno.h>, <limits.h>, <assert.h> und <stdlib.h> (falls verfügbar).
Hinweis
Da Python möglicherweise einige Präprozessor-Definitionen definiert, die die Standard-Header auf einigen Systemen beeinflussen, müssen Sie Python.h einschließen, bevor irgendwelche Standard-Header eingeschlossen werden.
Es wird empfohlen, PY_SSIZE_T_CLEAN immer zu definieren, bevor Python.h eingeschlossen wird. Siehe Argumente parsen und Werte erstellen für eine Beschreibung dieses Makros.
Alle vom Benutzer sichtbaren Namen, die von Python.h definiert werden (außer denen, die von den eingeschlossenen Standard-Headern definiert werden), haben eines der Präfixe Py oder _Py. Namen, die mit _Py beginnen, sind für die interne Verwendung durch die Python-Implementierung bestimmt und sollten von Erweiterungsautoren nicht verwendet werden. Strukturmembernamen haben kein reserviertes Präfix.
Hinweis
Benutzerdefinierter Code sollte niemals Namen definieren, die mit Py oder _Py beginnen. Dies verwirrt den Leser und gefährdet die Portabilität des Benutzercodes auf zukünftige Python-Versionen, die möglicherweise zusätzliche Namen mit einem dieser Präfixe definieren.
Die Header-Dateien werden typischerweise mit Python installiert. Unter Unix befinden sie sich in den Verzeichnissen prefix/include/pythonversion/ und exec_prefix/include/pythonversion/, wobei prefix und exec_prefix durch die entsprechenden Parameter des configure-Skripts von Python definiert werden und *version* '%d.%d' % sys.version_info[:2] ist. Unter Windows werden die Header in prefix/include installiert, wobei prefix das Verzeichnis ist, das dem Installer mitgeteilt wurde.
Um die Header einzubinden, legen Sie beide Verzeichnisse (falls unterschiedlich) in den Suchpfad für Includes Ihres Compilers. Legen Sie nicht die übergeordneten Verzeichnisse auf den Suchpfad und verwenden Sie dann #include <pythonX.Y/Python.h>; dies wird bei plattformübergreifenden Builds fehlschlagen, da die plattformunabhängigen Header unter prefix die plattformspezifischen Header von exec_prefix einschließen.
C++-Benutzer sollten beachten, dass, obwohl die API vollständig in C definiert ist, die Header-Dateien die Einstiegspunkte korrekt als extern "C" deklarieren. Daher ist nichts Besonderes zu tun, um die API aus C++ zu verwenden.
Nützliche Makros¶
Mehrere nützliche Makros sind in den Python-Header-Dateien definiert. Viele sind dort definiert, wo sie nützlich sind (z. B. Py_RETURN_NONE, PyMODINIT_FUNC). Andere von allgemeinerem Nutzen sind hier definiert. Dies ist keine vollständige Auflistung.
-
Py_ABS(x)¶
Gibt den absoluten Wert von
xzurück.Hinzugefügt in Version 3.3.
-
Py_ALWAYS_INLINE¶
Fordert den Compiler auf, eine statische Inline-Funktion immer zu inlinen. Der Compiler kann dies ignorieren und entscheiden, die Funktion nicht zu inlinen.
Es kann verwendet werden, um leistungskritische statische Inline-Funktionen beim Erstellen von Python im Debug-Modus mit deaktiviertem Function-Inlining einzubetten. MSC deaktiviert beispielsweise das Inlining von Funktionen beim Erstellen im Debug-Modus.
Das blinde Markieren einer statischen Inline-Funktion mit Py_ALWAYS_INLINE kann zu schlechteren Leistungen führen (z. B. aufgrund einer erhöhten Code-Größe). Der Compiler ist für die Kosten-/Nutzen-Analyse normalerweise intelligenter als der Entwickler.
Wenn Python im Debug-Modus erstellt wird (wenn das Makro
Py_DEBUGdefiniert ist), tut das MakroPy_ALWAYS_INLINEnichts.Es muss vor dem Rückgabetyp der Funktion angegeben werden. Verwendung
static inline Py_ALWAYS_INLINE int random(void) { return 4; }
Hinzugefügt in Version 3.11.
-
Py_CHARMASK(c)¶
Argument muss ein Zeichen oder eine Ganzzahl im Bereich [-128, 127] oder [0, 255] sein. Dieses Makro gibt
calsunsigned charzurück.
-
Py_DEPRECATED(version)¶
Verwenden Sie dies für veraltete Deklarationen. Das Makro muss vor dem Symbolnamen stehen.
Beispiel
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
Geändert in Version 3.8: MSVC-Unterstützung wurde hinzugefügt.
-
Py_GETENV(s)¶
Ähnlich wie
getenv(s), gibt aberNULLzurück, wenn-Eauf der Kommandozeile übergeben wurde (siehePyConfig.use_environment).
-
Py_MAX(x, y)¶
Gibt den maximalen Wert zwischen
xundyzurück.Hinzugefügt in Version 3.3.
-
Py_MEMBER_SIZE(type, member)¶
Gibt die Größe eines Struktur-
member(type) in Bytes zurück.Hinzugefügt in Version 3.6.
-
Py_MIN(x, y)¶
Gibt den minimalen Wert zwischen
xundyzurück.Hinzugefügt in Version 3.3.
-
Py_NO_INLINE¶
Deaktiviert das Inlining einer Funktion. Reduziert beispielsweise den Verbrauch des C-Stacks: nützlich bei LTO+PGO-Builds, die Code stark inlinen (siehe bpo-33720).
Verwendung
Py_NO_INLINE static int random(void) { return 4; }
Hinzugefügt in Version 3.11.
-
Py_STRINGIFY(x)¶
Konvertiert
xin einen C-String. Z. B. gibtPy_STRINGIFY(123)"123"zurück.Hinzugefügt in Version 3.4.
-
Py_UNREACHABLE()¶
Verwenden Sie dies, wenn Sie einen Code-Pfad haben, der per Design nicht erreichbar ist. Zum Beispiel in der
default:-Klausel in einerswitch-Anweisung, für die alle möglichen Werte incase-Anweisungen abgedeckt sind. Verwenden Sie dies an Stellen, an denen Sie versucht sein könnten, einenassert(0)- oderabort()-Aufruf einzufügen.Im Release-Modus hilft das Makro dem Compiler, den Code zu optimieren, und vermeidet eine Warnung über unerreichbaren Code. Zum Beispiel wird das Makro im Release-Modus mit
__builtin_unreachable()auf GCC implementiert.Eine Verwendung für
Py_UNREACHABLE()ist nach einem Aufruf einer Funktion, die niemals zurückkehrt, aber nicht als_Py_NO_RETURNdeklariert ist.Wenn ein Code-Pfad sehr unwahrscheinlich ist, aber unter außergewöhnlichen Umständen erreicht werden kann, darf dieses Makro nicht verwendet werden. Zum Beispiel unter Bedingungen mit geringem Speicher oder wenn ein Systemaufruf einen Wert außerhalb des erwarteten Bereichs zurückgibt. In diesem Fall ist es besser, den Fehler an den Aufrufer zu melden. Wenn der Fehler nicht an den Aufrufer gemeldet werden kann, kann
Py_FatalError()verwendet werden.Hinzugefügt in Version 3.7.
-
Py_UNUSED(arg)¶
Verwenden Sie dies für nicht verwendete Argumente in einer Funktionsdefinition, um Compiler-Warnungen zu unterdrücken. Beispiel:
int func(int a, int Py_UNUSED(b)) { return a; }.Hinzugefügt in Version 3.4.
-
PyDoc_STRVAR(name, str)¶
Erstellt eine Variable mit dem Namen
name, die in Docstrings verwendet werden kann. Wenn Python ohne Docstrings erstellt wird, ist der Wert leer.Verwenden Sie
PyDoc_STRVARfür Docstrings, um das Erstellen von Python ohne Docstrings zu unterstützen, wie in PEP 7 spezifiziert.Beispiel
PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element."); static PyMethodDef deque_methods[] = { // ... {"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc}, // ... }
-
PyDoc_STR(str)¶
Erstellt einen Docstring für den gegebenen Eingabe-String oder einen leeren String, wenn Docstrings deaktiviert sind.
Verwenden Sie
PyDoc_STRbei der Angabe von Docstrings, um das Erstellen von Python ohne Docstrings zu unterstützen, wie in PEP 7 spezifiziert.Beispiel
static PyMethodDef pysqlite_row_methods[] = { {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS, PyDoc_STR("Returns the keys of the row.")}, {NULL, NULL} };
Objekte, Typen und Referenzzähler¶
Die meisten Funktionen der Python/C-API haben ein oder mehrere Argumente sowie einen Rückgabewert vom Typ PyObject*. Dieser Typ ist ein Zeiger auf einen undurchsichtigen Datentyp, der ein beliebiges Python-Objekt darstellt. Da alle Python-Objekttypen von der Python-Sprache in den meisten Situationen gleich behandelt werden (z. B. Zuweisungen, Gültigkeitsregeln und Argumentübergabe), ist es nur passend, dass sie durch einen einzigen C-Typ repräsentiert werden. Fast alle Python-Objekte leben auf dem Heap: Sie deklarieren niemals eine automatische oder statische Variable vom Typ PyObject, nur Zeigervariablen vom Typ PyObject* können deklariert werden. Die einzige Ausnahme bilden die Typ-Objekte; da diese niemals freigegeben werden dürfen, sind sie typischerweise statische PyTypeObject-Objekte.
Alle Python-Objekte (auch Python-Ganzzahlen) haben einen Typ und einen Referenzzähler. Der Typ eines Objekts bestimmt, um welche Art von Objekt es sich handelt (z. B. eine Ganzzahl, eine Liste oder eine benutzerdefinierte Funktion; es gibt viele weitere, wie in Die Standard-Typenhierarchie erklärt). Für jeden der bekannten Typen gibt es ein Makro, um zu überprüfen, ob ein Objekt von diesem Typ ist; z. B. ist PyList_Check(a) wahr, wenn (und nur wenn) das von a referenzierte Objekt eine Python-Liste ist.
Referenzzähler¶
Der Referenzzähler ist wichtig, da heutige Computer eine endliche (und oft stark begrenzte) Speichergröße haben; er zählt, wie viele verschiedene Stellen eine starke Referenz auf ein Objekt haben. Eine solche Stelle könnte ein anderes Objekt, eine globale (oder statische) C-Variable oder eine lokale Variable in einer C-Funktion sein. Wenn die letzte starke Referenz auf ein Objekt freigegeben wird (d. h. sein Referenzzähler wird null), wird das Objekt freigegeben. Wenn es Referenzen auf andere Objekte enthält, werden diese Referenzen freigegeben. Diese anderen Objekte können dann freigegeben werden, wenn keine Referenzen mehr auf sie vorhanden sind, und so weiter. (Es gibt hier ein offensichtliches Problem mit sich gegenseitig referenzierenden Objekten; vorerst lautet die Lösung: „Tun Sie das nicht.“)
Referenzzähler werden immer explizit manipuliert. Der normale Weg ist die Verwendung des Makros Py_INCREF(), um eine neue Referenz auf ein Objekt zu erhalten (d. h. seinen Referenzzähler um eins erhöhen), und Py_DECREF(), um diese Referenz freizugeben (d. h. den Referenzzähler um eins verringern). Das Makro Py_DECREF() ist erheblich komplexer als das incref-Makro, da es prüfen muss, ob der Referenzzähler null wird, und dann den Dealloziator des Objekts aufrufen muss. Der Dealloziator ist ein Funktionszeiger, der in der Typenstruktur des Objekts enthalten ist. Der typspezifische Dealloziator kümmert sich um die Freigabe von Referenzen auf andere Objekte, die im Objekt enthalten sind, wenn es sich um einen zusammengesetzten Objekttyp handelt, wie z. B. eine Liste, und führt außerdem zusätzliche Finalisierungen durch, die erforderlich sind. Es besteht keine Chance, dass der Referenzzähler überläuft; zumindest so viele Bits werden verwendet, um den Referenzzähler zu speichern, wie es unterschiedliche Speicherorte im virtuellen Speicher gibt (vorausgesetzt, sizeof(Py_ssize_t) >= sizeof(void*)). Somit ist die Erhöhung des Referenzzählers eine einfache Operation.
Es ist nicht notwendig, eine starke Referenz (d. h. den Referenzzähler zu erhöhen) für jede lokale Variable zu halten, die einen Zeiger auf ein Objekt enthält. Theoretisch erhöht sich der Referenzzähler des Objekts um eins, wenn die Variable darauf gesetzt wird, und verringert sich um eins, wenn die Variable den Gültigkeitsbereich verlässt. Diese beiden heben sich jedoch auf, sodass der Referenzzähler am Ende unverändert bleibt. Der einzige wirkliche Grund für die Verwendung des Referenzzählers ist, die Freigabe des Objekts zu verhindern, solange unsere Variable darauf zeigt. Wenn wir wissen, dass mindestens eine andere Referenz auf das Objekt existiert, die mindestens so lange lebt wie unsere Variable, ist es nicht notwendig, vorübergehend eine neue starke Referenz (d. h. den Referenzzähler zu erhöhen) zu nehmen. Eine wichtige Situation, in der dies auftritt, sind Objekte, die als Argumente an C-Funktionen in einem Erweiterungsmodul übergeben werden, die von Python aufgerufen werden; der Aufrufmechanismus garantiert, eine Referenz auf jedes Argument für die Dauer des Aufrufs zu halten.
Ein häufiger Fehler ist jedoch, ein Objekt aus einer Liste zu extrahieren und es eine Weile aufzubewahren, ohne eine neue Referenz zu nehmen. Einige andere Operationen könnten das Objekt aus der Liste entfernen, diese Referenz freigeben und es möglicherweise freigeben. Die wirkliche Gefahr besteht darin, dass unschuldig aussehende Operationen beliebigen Python-Code aufrufen können, der dies tun könnte; es gibt einen Code-Pfad, der es ermöglicht, von einem Py_DECREF() zurück zum Benutzer zu fließen, sodass fast jede Operation potenziell gefährlich ist.
Ein sicherer Ansatz ist, immer die generischen Operationen zu verwenden (Funktionen, deren Name mit PyObject_, PyNumber_, PySequence_ oder PyMapping_ beginnt). Diese Operationen erstellen immer eine neue starke Referenz (d. h. erhöhen den Referenzzähler) des zurückgegebenen Objekts. Dies überlässt es dem Aufrufer, Py_DECREF() aufzurufen, wenn er mit dem Ergebnis fertig ist; dies wird bald zur zweiten Natur.
Details zu Referenzzählern¶
Das Referenzzählerverhalten von Funktionen in der Python/C-API wird am besten anhand des Besitzes von Referenzen erklärt. Besitz bezieht sich auf Referenzen, niemals auf Objekte (Objekte werden nicht besessen: sie werden immer geteilt). „Eine Referenz besitzen“ bedeutet, dafür verantwortlich zu sein, Py_DECREF darauf aufzurufen, wenn die Referenz nicht mehr benötigt wird. Der Besitz kann auch übertragen werden, was bedeutet, dass der Code, der den Besitz der Referenz erhält, dann dafür verantwortlich ist, sie schließlich durch Aufruf von Py_DECREF() oder Py_XDECREF() freizugeben, wenn sie nicht mehr benötigt wird - oder diese Verantwortung weiterzugeben (normalerweise an seinen Aufrufer). Wenn eine Funktion den Besitz einer Referenz an ihren Aufrufer weitergibt, erhält der Aufrufer eine neue Referenz. Wenn kein Besitz übertragen wird, leiht sich der Aufrufer die Referenz. Für eine geliehene Referenz muss nichts getan werden.
Umgekehrt gibt es bei der Übergabe einer Referenz auf ein Objekt durch eine aufrufende Funktion zwei Möglichkeiten: die Funktion stiehlt eine Referenz auf das Objekt, oder sie tut es nicht. *Eine Referenz stehlen* bedeutet, dass Sie, wenn Sie eine Referenz an eine Funktion übergeben, diese Funktion davon ausgeht, dass sie nun Eigentümer dieser Referenz ist und Sie nicht mehr dafür verantwortlich sind.
Nur wenige Funktionen stehlen Referenzen; die beiden bemerkenswerten Ausnahmen sind PyList_SetItem() und PyTuple_SetItem(), die eine Referenz auf das Element stehlen (aber nicht auf das Tupel oder die Liste, in die das Element eingefügt wird!). Diese Funktionen wurden entwickelt, um Referenzen zu stehlen, aufgrund eines gängigen Idioms zum Befüllen eines Tupels oder einer Liste mit neu erstellten Objekten; zum Beispiel könnte der Code zum Erstellen des Tupels (1, 2, "three") wie folgt aussehen (fehlerbehandlung vorerst vergessen; eine bessere Art, dies zu kodieren, ist unten gezeigt)
PyObject *t;
t = PyTuple_New(3);
PyTuple_SetItem(t, 0, PyLong_FromLong(1L));
PyTuple_SetItem(t, 1, PyLong_FromLong(2L));
PyTuple_SetItem(t, 2, PyUnicode_FromString("three"));
Hier gibt PyLong_FromLong() eine neue Referenz zurück, die sofort von PyTuple_SetItem() gestohlen wird. Wenn Sie ein Objekt weiter verwenden möchten, obwohl die Referenz darauf gestohlen wird, verwenden Sie Py_INCREF(), um eine weitere Referenz zu erhalten, bevor Sie die referenzstehlende Funktion aufrufen.
Übrigens ist PyTuple_SetItem() die einzige Möglichkeit, Tupel-Elemente zu setzen; PySequence_SetItem() und PyObject_SetItem() weigern sich, dies zu tun, da Tupel unveränderliche Datentypen sind. Sie sollten PyTuple_SetItem() nur für Tupel verwenden, die Sie selbst erstellen.
Der äquivalente Code zum Befüllen einer Liste kann mit PyList_New() und PyList_SetItem() geschrieben werden.
In der Praxis werden Sie diese Wege der Erstellung und des Befüllens von Tupeln oder Listen jedoch selten verwenden. Es gibt eine generische Funktion, Py_BuildValue(), die die meisten gängigen Objekte aus C-Werten erstellen kann, gesteuert durch einen Format-String. Zum Beispiel könnten die obigen beiden Codeblöcke durch Folgendes ersetzt werden (das auch die Fehlerbehandlung übernimmt)
PyObject *tuple, *list;
tuple = Py_BuildValue("(iis)", 1, 2, "three");
list = Py_BuildValue("[iis]", 1, 2, "three");
Es ist viel üblicher, PyObject_SetItem() und ähnliche Funktionen mit Elementen zu verwenden, deren Referenzen Sie nur ausleihen, wie z. B. Argumente, die an die von Ihnen geschriebene Funktion übergeben wurden. In diesem Fall ist ihr Verhalten bezüglich Referenzen viel sinnvoller, da Sie keine neue Referenz nehmen müssen, nur um diese Referenz wegzugeben („sie stehlen lassen“). Zum Beispiel setzt diese Funktion alle Elemente einer Liste (eigentlich jede veränderliche Sequenz) auf ein bestimmtes Element
int
set_all(PyObject *target, PyObject *item)
{
Py_ssize_t i, n;
n = PyObject_Length(target);
if (n < 0)
return -1;
for (i = 0; i < n; i++) {
PyObject *index = PyLong_FromSsize_t(i);
if (!index)
return -1;
if (PyObject_SetItem(target, index, item) < 0) {
Py_DECREF(index);
return -1;
}
Py_DECREF(index);
}
return 0;
}
Die Situation ist für Funktionsrückgabewerte etwas anders. Während die Übergabe einer Referenz an die meisten Funktionen Ihre Verantwortung für diese Referenz nicht ändert, geben viele Funktionen, die eine Referenz auf ein Objekt zurückgeben, Ihnen den Besitz der Referenz. Der Grund ist einfach: In vielen Fällen wird das zurückgegebene Objekt im Moment erstellt, und die Referenz, die Sie erhalten, ist die einzige Referenz auf das Objekt. Daher geben die generischen Funktionen, die Objekt-Referenzen zurückgeben, wie PyObject_GetItem() und PySequence_GetItem(), immer eine neue Referenz zurück (der Aufrufer wird Eigentümer der Referenz).
Es ist wichtig zu erkennen, dass der Besitz einer von einer Funktion zurückgegebenen Referenz nur davon abhängt, welche Funktion Sie aufrufen — die Gefiederung (die Art des Objekts, das als Argument an die Funktion übergeben wird) spielt keine Rolle! Wenn Sie also ein Element aus einer Liste mit PyList_GetItem() extrahieren, besitzen Sie die Referenz nicht — aber wenn Sie dasselbe Element aus derselben Liste mit PySequence_GetItem() (was zufällig genau dieselben Argumente verwendet) erhalten, dann besitzen Sie eine Referenz auf das zurückgegebene Objekt.
Hier ist ein Beispiel, wie Sie eine Funktion schreiben könnten, die die Summe der Elemente in einer Liste von Ganzzahlen berechnet; einmal mit PyList_GetItem() und einmal mit PySequence_GetItem().
long
sum_list(PyObject *list)
{
Py_ssize_t i, n;
long total = 0, value;
PyObject *item;
n = PyList_Size(list);
if (n < 0)
return -1; /* Not a list */
for (i = 0; i < n; i++) {
item = PyList_GetItem(list, i); /* Can't fail */
if (!PyLong_Check(item)) continue; /* Skip non-integers */
value = PyLong_AsLong(item);
if (value == -1 && PyErr_Occurred())
/* Integer too big to fit in a C long, bail out */
return -1;
total += value;
}
return total;
}
long
sum_sequence(PyObject *sequence)
{
Py_ssize_t i, n;
long total = 0, value;
PyObject *item;
n = PySequence_Length(sequence);
if (n < 0)
return -1; /* Has no length */
for (i = 0; i < n; i++) {
item = PySequence_GetItem(sequence, i);
if (item == NULL)
return -1; /* Not a sequence, or other failure */
if (PyLong_Check(item)) {
value = PyLong_AsLong(item);
Py_DECREF(item);
if (value == -1 && PyErr_Occurred())
/* Integer too big to fit in a C long, bail out */
return -1;
total += value;
}
else {
Py_DECREF(item); /* Discard reference ownership */
}
}
return total;
}
Typen¶
Es gibt wenige andere Datentypen, die eine wichtige Rolle in der Python/C-API spielen; die meisten sind einfache C-Typen wie int, long, double und char*. Einige Strukturtypen werden verwendet, um statische Tabellen zu beschreiben, die zur Auflistung der von einem Modul exportierten Funktionen oder der Datenattribute eines neuen Objekttyps dienen, und ein weiterer wird zur Beschreibung des Werts einer komplexen Zahl verwendet. Diese werden zusammen mit den Funktionen besprochen, die sie verwenden.
-
type Py_ssize_t¶
- Teil der Stable ABI.
Ein vorzeichenbehafteter ganzzahliger Typ, so dass
sizeof(Py_ssize_t) == sizeof(size_t). C99 definiert so etwas nicht direkt (size_t ist ein vorzeichenloser ganzzahliger Typ). Siehe PEP 353 für Details.PY_SSIZE_T_MAXist der größte positive Wert vom TypPy_ssize_t.
Ausnahmen¶
Der Python-Programmierer muss sich nur dann mit Ausnahmen befassen, wenn eine spezifische Fehlerbehandlung erforderlich ist; unbehandelte Ausnahmen werden automatisch an den Aufrufer weitergeleitet, dann an den Aufrufer des Aufrufers und so weiter, bis sie den Interpreter auf der obersten Ebene erreichen, wo sie dem Benutzer zusammen mit einem Stack-Traceback gemeldet werden.
Für C-Programmierer muss die Fehlerprüfung jedoch immer explizit erfolgen. Alle Funktionen in der Python/C-API können Ausnahmen auslösen, es sei denn, es wird in der Dokumentation einer Funktion ausdrücklich etwas anderes behauptet. Im Allgemeinen setzt eine Funktion, wenn sie einen Fehler feststellt, eine Ausnahme, verwirft alle Objektverweise, die sie besitzt, und gibt einen Fehlerindikator zurück. Sofern nicht anders dokumentiert, ist dieser Indikator entweder NULL oder -1, abhängig vom Rückgabetyp der Funktion. Einige wenige Funktionen geben ein boolesches True/False-Ergebnis zurück, wobei False einen Fehler anzeigt. Sehr wenige Funktionen geben keinen expliziten Fehlerindikator zurück oder haben einen mehrdeutigen Rückgabewert und erfordern eine explizite Prüfung auf Fehler mit PyErr_Occurred(). Diese Ausnahmen werden immer explizit dokumentiert.
Der Ausnahmezustand wird im Thread-spezifischen Speicher verwaltet (dies entspricht der Verwendung von globalem Speicher in einer nicht-threaded Anwendung). Ein Thread kann sich in einem von zwei Zuständen befinden: Eine Ausnahme ist aufgetreten oder nicht. Die Funktion PyErr_Occurred() kann verwendet werden, um dies zu überprüfen: Sie gibt einen ausgeliehenen Verweis auf das Ausnahmetyp-Objekt zurück, wenn eine Ausnahme aufgetreten ist, und andernfalls NULL. Es gibt eine Reihe von Funktionen, um den Ausnahmezustand zu setzen: PyErr_SetString() ist die gebräuchlichste (wenn auch nicht die allgemeinste) Funktion zum Setzen des Ausnahmezustands, und PyErr_Clear() löscht den Ausnahmezustand.
Der vollständige Ausnahmezustand besteht aus drei Objekten (die alle NULL sein können): dem Ausnahmetyp, dem entsprechenden Ausnahme-Wert und dem Traceback. Diese haben die gleiche Bedeutung wie das Python-Ergebnis von sys.exc_info(); sie sind jedoch nicht dasselbe: Die Python-Objekte repräsentieren die letzte Ausnahme, die von einer Python try ... except-Anweisung behandelt wird, während der Ausnahmezustand auf C-Ebene nur existiert, solange eine Ausnahme zwischen C-Funktionen weitergegeben wird, bis sie die Hauptschleife des Python-Bytecode-Interpreters erreicht, die für die Übertragung an sys.exc_info() und verwandte Funktionen zuständig ist.
Beachten Sie, dass ab Python 1.5 der bevorzugte, Thread-sichere Weg, um von Python-Code auf den Ausnahmezustand zuzugreifen, der Aufruf der Funktion sys.exc_info() ist, die den Thread-spezifischen Ausnahmezustand für Python-Code zurückgibt. Außerdem haben sich die Semantiken beider Wege zum Zugriff auf den Ausnahmezustand geändert, so dass eine Funktion, die eine Ausnahme abfängt, den Ausnahmezustand ihres Threads speichert und wiederherstellt, um den Ausnahmezustand ihres Aufrufers zu erhalten. Dies verhindert häufige Fehler in der Ausnahmebehandlungslogik, die dadurch verursacht werden, dass eine harmlos aussehende Funktion die behandelte Ausnahme überschreibt; es reduziert auch die oft unerwünschte Lebensdauerverlängerung für Objekte, auf die von den Stack-Frames im Traceback verwiesen wird.
Als allgemeines Prinzip sollte eine Funktion, die eine andere Funktion aufruft, um eine Aufgabe auszuführen, überprüfen, ob die aufgerufene Funktion eine Ausnahme ausgelöst hat, und wenn ja, den Ausnahmezustand an ihren Aufrufer weitergeben. Sie sollte alle eigenen Objektverweise verwerfen und einen Fehlerindikator zurückgeben, aber sie sollte keine weitere Ausnahme setzen – das würde die gerade ausgelöste Ausnahme überschreiben und wichtige Informationen über die genaue Ursache des Fehlers verlieren.
Ein einfaches Beispiel für die Erkennung und Weitergabe von Ausnahmen wird im obigen Beispiel sum_sequence() gezeigt. Es stellt sich heraus, dass dieses Beispiel keine eigenen Referenzen bereinigen muss, wenn es einen Fehler erkennt. Die folgende Beispiel-Funktion zeigt eine Fehlerbereinigung. Zuerst, um Sie daran zu erinnern, warum Sie Python mögen, zeigen wir den entsprechenden Python-Code
def incr_item(dict, key):
try:
item = dict[key]
except KeyError:
item = 0
dict[key] = item + 1
Hier ist der entsprechende C-Code, in seiner ganzen Pracht
int
incr_item(PyObject *dict, PyObject *key)
{
/* Objects all initialized to NULL for Py_XDECREF */
PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
int rv = -1; /* Return value initialized to -1 (failure) */
item = PyObject_GetItem(dict, key);
if (item == NULL) {
/* Handle KeyError only: */
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
/* Clear the error and use zero: */
PyErr_Clear();
item = PyLong_FromLong(0L);
if (item == NULL)
goto error;
}
const_one = PyLong_FromLong(1L);
if (const_one == NULL)
goto error;
incremented_item = PyNumber_Add(item, const_one);
if (incremented_item == NULL)
goto error;
if (PyObject_SetItem(dict, key, incremented_item) < 0)
goto error;
rv = 0; /* Success */
/* Continue with cleanup code */
error:
/* Cleanup code, shared by success and failure path */
/* Use Py_XDECREF() to ignore NULL references */
Py_XDECREF(item);
Py_XDECREF(const_one);
Py_XDECREF(incremented_item);
return rv; /* -1 for error, 0 for success */
}
Dieses Beispiel stellt eine empfohlene Verwendung der goto-Anweisung in C dar! Es illustriert die Verwendung von PyErr_ExceptionMatches() und PyErr_Clear() zur Behandlung spezifischer Ausnahmen und die Verwendung von Py_XDECREF() zur Entsorgung von eigenen Referenzen, die NULL sein können (beachten Sie das 'X' im Namen; Py_DECREF() würde abstürzen, wenn er mit einer NULL-Referenz konfrontiert wird). Es ist wichtig, dass die Variablen, die zur Speicherung eigener Referenzen verwendet werden, für diese Funktionalität mit NULL initialisiert werden; ebenso wird der vorgeschlagene Rückgabewert mit -1 (Fehler) initialisiert und nur dann auf Erfolg gesetzt, wenn der letzte Aufruf erfolgreich war.
Python einbetten¶
Die einzige wichtige Aufgabe, um die sich die Eibetter (im Gegensatz zu Erweiterungsentwicklern) des Python-Interpreters kümmern müssen, ist die Initialisierung und möglicherweise die Finalisierung des Python-Interpreters. Die meiste Funktionalität des Interpreters kann erst nach der Initialisierung des Interpreters verwendet werden.
Die grundlegende Initialisierungsfunktion ist Py_Initialize(). Diese initialisiert die Tabelle der geladenen Module und erstellt die grundlegenden Module builtins, __main__ und sys. Sie initialisiert auch den Modulsuchpfad (sys.path).
Py_Initialize() setzt nicht die "Skript-Argumentenliste" (sys.argv). Wenn diese Variable von Python-Code benötigt wird, der später ausgeführt wird, müssen PyConfig.argv und PyConfig.parse_argv gesetzt werden: siehe Python Initialization Configuration.
Auf den meisten Systemen (insbesondere unter Unix und Windows, obwohl die Details leicht unterschiedlich sind) berechnet Py_Initialize() den Modulsuchpfad basierend auf seiner besten Schätzung für den Speicherort des Standard-Python-Interpreter-Executables, unter der Annahme, dass die Python-Bibliothek an einem festen Ort relativ zum Python-Interpreter-Executable gefunden wird. Insbesondere sucht es nach einem Verzeichnis namens lib/pythonX.Y relativ zum übergeordneten Verzeichnis, in dem das Executable namens python im Shell-Suchpfad (der Umgebungsvariable PATH) gefunden wird.
Wenn beispielsweise das Python-Executable in /usr/local/bin/python gefunden wird, wird davon ausgegangen, dass sich die Bibliotheken in /usr/local/lib/pythonX.Y befinden. (Tatsächlich ist dieser spezielle Pfad auch der "Fallback"-Speicherort, der verwendet wird, wenn kein Executable mit dem Namen python im PATH gefunden wird.) Der Benutzer kann dieses Verhalten überschreiben, indem er die Umgebungsvariable PYTHONHOME setzt oder zusätzliche Verzeichnisse vor dem Standardpfad einfügt, indem er PYTHONPATH setzt.
Die eingebettete Anwendung kann die Suche steuern, indem sie PyConfig.program_name setzt, bevor sie Py_InitializeFromConfig() aufruft. Beachten Sie, dass PYTHONHOME dies immer noch überschreibt und PYTHONPATH immer noch vor dem Standardpfad eingefügt wird. Eine Anwendung, die die vollständige Kontrolle wünscht, muss ihre eigene Implementierung von Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix() und Py_GetProgramFullPath() (alle definiert in Modules/getpath.c) bereitstellen.
Manchmal ist es wünschenswert, Python zu "deinitialisieren". Zum Beispiel möchte die Anwendung neu starten (einen weiteren Aufruf von Py_Initialize() machen) oder die Anwendung ist einfach fertig mit ihrer Verwendung von Python und möchte von Python zugewiesenen Speicher freigeben. Dies kann durch den Aufruf von Py_FinalizeEx() erreicht werden. Die Funktion Py_IsInitialized() gibt wahr zurück, wenn Python sich im initialisierten Zustand befindet. Mehr Informationen zu diesen Funktionen finden Sie in einem späteren Kapitel. Beachten Sie, dass Py_FinalizeEx() nicht allen vom Python-Interpreter zugewiesenen Speicher freigibt, z.B. kann Speicher, der von Erweiterungsmodulen zugewiesen wurde, derzeit nicht freigegeben werden.
Debug-Builds¶
Python kann mit verschiedenen Makros kompiliert werden, um zusätzliche Prüfungen des Interpreters und von Erweiterungsmodulen zu aktivieren. Diese Prüfungen verursachen in der Regel einen hohen Laufzeit-Overhead und sind daher standardmäßig nicht aktiviert.
Eine vollständige Liste der verschiedenen Arten von Debug-Builds finden Sie in der Datei Misc/SpecialBuilds.txt in der Python-Quellcode-Distribution. Es gibt Builds, die die Verfolgung von Referenzzählungen, das Debugging des Speicherallokators oder das Low-Level-Profiling der Hauptinterpreterschleife unterstützen. Nur die am häufigsten verwendeten Builds werden im Rest dieses Abschnitts beschrieben.
-
Py_DEBUG¶
Das Kompilieren des Interpreters mit dem definierten Makro Py_DEBUG erzeugt das, was allgemein als Debug-Build von Python bezeichnet wird. Py_DEBUG wird im Unix-Build aktiviert, indem --with-pydebug zum Befehl ./configure hinzugefügt wird. Es wird auch durch die Anwesenheit des nicht-Python-spezifischen Makros _DEBUG impliziert. Wenn Py_DEBUG im Unix-Build aktiviert ist, wird die Compiler-Optimierung deaktiviert.
Zusätzlich zum unten beschriebenen Referenzzählungs-Debugging werden zusätzliche Prüfungen durchgeführt. Siehe Python Debug Build.
Das Definieren von Py_TRACE_REFS aktiviert die Referenzverfolgung (siehe die configure --with-trace-refs Option). Wenn dies definiert ist, wird eine zirkuläre doppelt verkettete Liste aktiver Objekte durch Hinzufügen von zwei zusätzlichen Feldern zu jedem PyObject gepflegt. Die gesamten Allokationen werden ebenfalls verfolgt. Beim Beenden werden alle vorhandenen Referenzen ausgegeben. (Im interaktiven Modus geschieht dies nach jeder vom Interpreter ausgeführten Anweisung.)
Weitere detaillierte Informationen finden Sie in Misc/SpecialBuilds.txt in der Python-Quellcode-Distribution.
Empfohlene Drittanbieter-Tools¶
Die folgenden Drittanbieter-Tools bieten sowohl einfachere als auch anspruchsvollere Ansätze zur Erstellung von C-, C++- und Rust-Erweiterungen für Python
Die Verwendung solcher Tools kann helfen, Code zu vermeiden, der eng an eine bestimmte Version von CPython gebunden ist, Referenzzählungsfehler zu vermeiden und sich mehr auf Ihren eigenen Code zu konzentrieren als auf die Verwendung der CPython-API. Im Allgemeinen können neue Versionen von Python durch Aktualisieren des Tools unterstützt werden, und Ihr Code wird oft automatisch neuere und effizientere APIs verwenden. Einige Tools unterstützen auch das Kompilieren für andere Implementierungen von Python aus einer einzigen Quellcodebasis.
Diese Projekte werden nicht von denselben Personen betreut, die Python pflegen, und Probleme müssen direkt mit den Projekten besprochen werden. Denken Sie daran, zu prüfen, ob das Projekt noch gewartet und unterstützt wird, da die obige Liste veraltet sein kann.
Siehe auch
- Python Packaging User Guide: Binäre Erweiterungen
Der Python Packaging User Guide behandelt nicht nur mehrere verfügbare Tools, die die Erstellung von Binärerweiterungen vereinfachen, sondern diskutiert auch die verschiedenen Gründe, warum die Erstellung eines Erweiterungsmoduls überhaupt wünschenswert sein kann.