Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 384 – Definition einer stabilen ABI

Autor:
Martin von Löwis <martin at v.loewis.de>
Status:
Final
Typ:
Standards Track
Erstellt:
17. Mai 2009
Python-Version:
3.2
Post-History:


Inhaltsverzeichnis

Wichtig

Dieser PEP ist ein historisches Dokument. Die aktuelle, kanonische Dokumentation finden Sie jetzt unter C API-Stabilität (Benutzerdokumentation) und Änderung der C API von Python (Entwicklerdokumentation).

×

Siehe PEP 1, um Änderungen vorzuschlagen.

Zusammenfassung

Derzeit führt jede Feature-Version einen neuen Namen für die Python-DLL unter Windows ein und kann zu Inkompatibilitäten für Erweiterungsmodule unter Unix führen. Dieser PEP schlägt vor, eine stabile Sammlung von API-Funktionen zu definieren, die für die Lebensdauer von Python 3 garantiert verfügbar sind und auch über Versionen hinweg binärkompatibel bleiben. Erweiterungsmodule und Anwendungen, die Python einbetten, können mit verschiedenen Feature-Versionen arbeiten, solange sie sich auf diese stabile ABI beschränken.

Begründung

Die primäre Ursache für ABI-Inkompatibilitäten sind Änderungen am Layout von In-Memory-Strukturen. Beispielsweise haben sich die Art und Weise, wie String-Interning funktioniert, oder der Datentyp, der zur Darstellung der Größe eines Objekts verwendet wird, während der Lebensdauer von Python 2.x geändert. Infolgedessen würden Erweiterungsmodule, die direkten Zugriff auf Felder von Strings, Listen oder Tupeln haben, fehlschlagen, wenn ihr Code in eine neuere Version des Interpreters geladen wird, ohne neu kompiliert zu werden: Offsets anderer Felder könnten sich geändert haben, was dazu führt, dass die Erweiterungsmodule auf die falschen Daten zugreifen.

In einigen Fällen betreffen die Inkompatibilitäten nur interne Objekte des Interpreters, wie z. B. Frame- oder Code-Objekte. Zum Beispiel hat sich die Art und Weise, wie Zeilennummern dargestellt werden, während der Lebensdauer von 2.x geändert, ebenso wie die Art und Weise, wie lokale Variablen gespeichert werden (aufgrund der Einführung von Closures). Obwohl die meisten Anwendungen diese Objekte wahrscheinlich nie verwendet haben, erforderte die Änderung dieser Objekte die Änderung von PYTHON_API_VERSION.

Unter Linux sind Änderungen an der ABI oft kein großes Problem: Das System bietet eine Standard-Python-Installation, und viele Erweiterungsmodule werden bereits vorkompiliert für diese Version bereitgestellt. Wenn zusätzliche Module oder zusätzliche Python-Versionen benötigt werden, können Benutzer sie typischerweise selbst auf dem System kompilieren, was zu Modulen führt, die die richtige ABI verwenden.

Unter Windows sind mehrere gleichzeitige Installationen verschiedener Python-Versionen üblich, und Erweiterungsmodule werden von ihren Autoren kompiliert, nicht von Endbenutzern. Um das Risiko von ABI-Inkompatibilitäten zu verringern, führt Python derzeit für jede Feature-Version einen neuen DLL-Namen pythonXY.dll ein, unabhängig davon, ob ABI-Inkompatibilitäten tatsächlich bestehen.

Mit diesem PEP wird es möglich sein, die Abhängigkeit von binären Erweiterungsmodulen von einer bestimmten Python-Feature-Version zu reduzieren, und Anwendungen, die Python einbetten, können mit verschiedenen Versionen arbeiten.

Spezifikation

Die ABI-Spezifikation besteht aus zwei Teilen: einer API-Spezifikation, die angibt, welche Funktionen (Gruppen) für die Verwendung mit der ABI verfügbar sind, und einer Link-Spezifikation, die angibt, mit welchen Bibliotheken verknüpft werden soll. Die tatsächliche ABI (Layout von Strukturen im Speicher, Funktionsaufrufkonventionen) wird nicht spezifiziert, sondern vom Compiler impliziert. Als Empfehlung wird für ausgewählte Plattformen eine spezifische ABI empfohlen.

Während der Entwicklung von Python werden neue ABI-Funktionen hinzugefügt. Anwendungen, die diese verwenden, haben dann eine Anforderung an eine Mindestversion von Python; dieser PEP bietet keinen Mechanismus für solche Anwendungen, zurückzufallen, wenn die Python-Bibliothek zu alt ist.

Terminologie

Anwendungen und Erweiterungsmodule, die diese ABI nutzen möchten, werden im Folgenden kollektiv als „Anwendungen“ bezeichnet.

Header-Dateien und Präprozessor-Definitionen

Anwendungen sollen nur die Header-Datei Python.h einbinden (bevor irgendwelche System-Header eingebunden werden) oder optional pyconfig.h und dann Python.h einbinden.

Während der Kompilierung von Anwendungen muss das Präprozessor-Makro Py_LIMITED_API definiert sein. Dies verbirgt alle Definitionen, die nicht Teil der ABI sind.

Strukturen

Nur die folgenden Strukturen und Strukturfelder sind für Anwendungen zugänglich

  • PyObject (ob_refcnt, ob_type)
  • PyVarObject (ob_base, ob_size)
  • PyMethodDef (ml_name, ml_meth, ml_flags, ml_doc)
  • PyMemberDef (name, type, offset, flags, doc)
  • PyGetSetDef (name, get, set, doc, closure)
  • PyModuleDefBase (ob_base, m_init, m_index, m_copy)
  • PyModuleDef (m_base, m_name, m_doc, m_size, m_methods, m_traverse, m_clear, m_free)
  • PyStructSequence_Field (name, doc)
  • PyStructSequence_Desc (name, doc, fields, sequence)
  • PyType_Slot (siehe unten)
  • PyType_Spec (siehe unten)

Die Zugriffs-Makros für diese Felder (Py_REFCNT, Py_TYPE, Py_SIZE) sind ebenfalls für Anwendungen verfügbar.

Die folgenden Typen sind verfügbar, aber opak (d. h. unvollständig)

  • PyThreadState
  • PyInterpreterState
  • struct _frame
  • struct symtable
  • struct _node
  • PyWeakReference
  • PyLongObject
  • PyTypeObject

Typ-Objekte

Die Struktur von Typobjekten ist für Anwendungen nicht verfügbar; die Deklaration von „statischen“ Typobjekten ist nicht mehr möglich (für Anwendungen, die diese ABI verwenden). Stattdessen werden Typobjekte dynamisch erstellt. Um eine einfache Erstellung von Typen zu ermöglichen (insbesondere um Funktionszeiger leicht auszufüllen), sind die folgenden Strukturen und Funktionen verfügbar

typedef struct{
  int slot;    /* slot id, see below */
  void *pfunc; /* function pointer */
} PyType_Slot;

typedef struct{
  const char* name;
  int basicsize;
  int itemsize;
  unsigned int flags;
  PyType_Slot *slots; /* terminated by slot==0. */
} PyType_Spec;

PyObject* PyType_FromSpec(PyType_Spec*);

Um einen Slot anzugeben, muss eine eindeutige Slot-ID angegeben werden. Neue Python-Versionen können neue Slot-IDs einführen, aber Slot-IDs werden niemals wiederverwendet. Slots können veraltet sein, aber sie werden während Python 3.x weiterhin unterstützt.

Die Slot-IDs sind benannt wie die Feldnamen der Strukturen, die die Zeiger in Python 3.1 halten, mit einem hinzugefügten Präfix Py_ (d. h. Py_tp_dealloc anstelle von nur tp_dealloc)

  • tp_dealloc, tp_getattr, tp_setattr, tp_repr, tp_hash, tp_call, tp_str, tp_getattro, tp_setattro, tp_doc, tp_traverse, tp_clear, tp_richcompare, tp_iter, tp_iternext, tp_methods, tp_base, tp_descr_get, tp_descr_set, tp_init, tp_alloc, tp_new, tp_is_gc, tp_bases, tp_del
  • nb_add nb_subtract nb_multiply nb_remainder nb_divmod nb_power nb_negative nb_positive nb_absolute nb_bool nb_invert nb_lshift nb_rshift nb_and nb_xor nb_or nb_int nb_float nb_inplace_add nb_inplace_subtract nb_inplace_multiply nb_inplace_remainder nb_inplace_power nb_inplace_lshift nb_inplace_rshift nb_inplace_and nb_inplace_xor nb_inplace_or nb_floor_divide nb_true_divide nb_inplace_floor_divide nb_inplace_true_divide nb_index
  • sq_length sq_concat sq_repeat sq_item sq_ass_item sq_contains sq_inplace_concat sq_inplace_repeat
  • mp_length mp_subscript mp_ass_subscript

Die folgenden Felder können während der Typdefinition nicht gesetzt werden: - tp_dict tp_mro tp_cache tp_subclasses tp_weaklist tp_print - tp_weaklistoffset tp_dictoffset

Typedefs

Zusätzlich zu den Typedefs für die oben aufgeführten Strukturen sind die folgenden Typedefs verfügbar. Ihre Aufnahme in die ABI bedeutet, dass der zugrunde liegende Typ auf einer Plattform nicht geändert werden darf (auch wenn er sich zwischen den Plattformen unterscheiden kann).

  • Py_uintptr_t Py_intptr_t Py_ssize_t
  • unaryfunc binaryfunc ternaryfunc inquiry lenfunc ssizeargfunc ssizessizeargfunc ssizeobjargproc ssizessizeobjargproc objobjargproc objobjproc visitproc traverseproc destructor getattrfunc getattrofunc setattrfunc setattrofunc reprfunc hashfunc richcmpfunc getiterfunc iternextfunc descrgetfunc descrsetfunc initproc newfunc allocfunc
  • PyCFunction PyCFunctionWithKeywords PyNoArgsFunction PyCapsule_Destructor
  • getter setter
  • PyOS_sighandler_t
  • PyGILState_STATE
  • Py_UCS4

Insbesondere ist Py_UNICODE nicht als Typedef verfügbar, da dieselbe Python-Version unterschiedliche Definitionen davon auf derselben Plattform verwenden kann (abhängig davon, ob sie schmale oder breite Code-Einheiten verwendet). Anwendungen, die auf den Inhalt eines Unicode-Strings zugreifen müssen, können ihn in wchar_t konvertieren.

Funktionen und Funktions-ähnliche Makros

Standardmäßig sind alle Funktionen verfügbar, es sei denn, sie sind unten ausgeschlossen. Ob eine Funktion dokumentiert ist oder nicht, spielt keine Rolle.

Funktions-ähnliche Makros (insbesondere Feldzugriffs-Makros) bleiben für Anwendungen verfügbar, werden aber durch Funktionsaufrufe ersetzt (es sei denn, ihre Definition bezieht sich nur auf Funktionen der ABI, wie die verschiedenen _Check-Makros).

ABI-Funktionsdeklarationen werden ihre Parameter oder Rückgabetypen nicht ändern. Wenn eine Änderung der Signatur notwendig wird, wird eine neue Funktion eingeführt. Wenn die neue Funktion quellkompatibel ist (z. B. wenn sich nur der Rückgabetyp ändert), kann ein Alias-Makro hinzugefügt werden, um Aufrufe an die neue Funktion umzuleiten, wenn die Anwendung neu kompiliert wird.

Wenn die fortgesetzte Bereitstellung der alten Funktion nicht möglich ist, kann sie veraltet und dann entfernt werden, was dazu führt, dass Anwendungen, die diese Funktion verwenden, fehlschlagen.

Ausgeschlossene Funktionen

Alle Funktionen, die mit _Py beginnen, sind für Anwendungen nicht verfügbar. Außerdem sind alle Funktionen, die Parametertypen erwarten, die für Anwendungen nicht verfügbar sind, von der ABI ausgeschlossen, wie z. B. PyAST_FromNode (das einen node* erwartet).

Funktionen, die in den folgenden Header-Dateien deklariert sind, sind nicht Teil der ABI

  • bytes_methods.h
  • cellobject.h
  • classobject.h
  • code.h
  • compile.h
  • datetime.h
  • dtoa.h
  • frameobject.h
  • funcobject.h
  • genobject.h
  • longintrepr.h
  • parsetok.h
  • pyarena.h
  • pyatomic.h
  • pyctype.h
  • pydebug.h
  • pytime.h
  • symtable.h
  • token.h
  • ucnhash.h

Zusätzlich sind Funktionen, die FILE* erwarten, nicht Teil der ABI, um eine Abhängigkeit von einer bestimmten Version der Microsoft C Runtime DLL unter Windows zu vermeiden.

Modul- und Typeninitialisierungs- und -finalisierungsfunktionen sind nicht verfügbar (PyByteArray_Init, PyOS_FiniInterrupts und alle Funktionen, die auf _Fini oder _ClearFreeList enden).

Mehrere Funktionen, die sich mit Interpreter-Implementierungsdetails befassen, sind nicht verfügbar

  • PyInterpreterState_Head, PyInterpreterState_Next, PyInterpreterState_ThreadHead, PyThreadState_Next
  • Py_SubversionRevision, Py_SubversionShortBranch

PyStructSequence_InitType ist nicht verfügbar, da sie erfordert, dass der Aufrufer ein statisches Typobjekt bereitstellt.

Py_FatalError wird von pydebug.h in eine andere Header-Datei (z. B. pyerrors.h) verschoben.

Die genaue Liste der verfügbaren Funktionen ist in der Moduldefinitionsdatei für python3.dll unter Windows angegeben [1].

Globale Variablen

Globale Variablen, die Typen und Ausnahmen darstellen, sind für Anwendungen verfügbar. Darüber hinaus sind ausgewählte globale Variablen, auf die in Makros verwiesen wird (wie Py_True und Py_False), verfügbar.

Eine vollständige Liste der Definitionen globaler Variablen ist in der Datei python3.def angegeben [1]; die als DATA deklarierten sind Variablen.

Andere Makros

Alle Makros, die symbolische Konstanten definieren, sind für Anwendungen verfügbar; die numerischen Werte werden sich nicht ändern.

Zusätzlich sind die folgenden Makros verfügbar

  • Py_BEGIN_ALLOW_THREADS, Py_BLOCK_THREADS, Py_UNBLOCK_THREADS, Py_END_ALLOW_THREADS

Die Puffer-Schnittstelle

Die Puffer-Schnittstelle (Typ Py_buffer, Typ-Slots bf_getbuffer und bf_releasebuffer usw.) wurde aus der ABI weggelassen, da die Stabilität der Py_buffer-Struktur zu diesem Zeitpunkt nicht klar ist. Die Aufnahme in die ABI kann in zukünftigen Versionen in Betracht gezogen werden.

Signaturänderungen

Eine Reihe von Funktionen erwartet derzeit eine bestimmte Struktur, obwohl Aufrufer typischerweise PyObject* zur Verfügung haben. Diese wurden dahingehend geändert, dass sie PyObject* als Parameter erwarten; dies führt zu Warnungen in Anwendungen, die derzeit explizit auf den Parametertyp umwandeln. Diese Funktionen sind PySlice_GetIndices, PySlice_GetIndicesEx, PyUnicode_AsWideChar und PyEval_EvalCode.

Verknüpfung

Unter Windows sollen Anwendungen gegen python3.dll verknüpft werden; eine Importbibliothek python3.lib wird verfügbar sein. Diese DLL leitet alle ihre API-Funktionen über /export-Linker-Optionen an die vollständige Interpreter-DLL, d. h. python3y.dll, weiter.

Unter Unix-Systemen wird die ABI typischerweise vom python-Executable selbst bereitgestellt. PyModule_Create wird geändert, um 3 als API-Version zu übergeben, wenn das Erweiterungsmodul mit Py_LIMITED_API kompiliert wurde; die Versionsprüfung für die API-Version akzeptiert entweder 3 oder die aktuelle PYTHON_API_VERSION als konform. Wenn Python als Shared Library kompiliert wird, wird es sowohl als libpython3.so als auch als libpython3.y.so installiert; Anwendungen, die diesem PEP entsprechen, sollten sich dann mit ersterer verknüpfen (Erweiterungsmodule können sich weiterhin ohne libpython Shared Object verknüpfen, sondern auf Laufzeitverknüpfung setzen). Die ABI-Version ist symbolisch als PYTHON_ABI_VERSION verfügbar.

Ebenfalls unter Unix wird der PEP 3149 Tag abi<PYTHON_ABI_VERSION> in Dateinamen von Erweiterungsmodulen akzeptiert. Es wird keine Prüfung durchgeführt, ob Dateien mit diesem Namen tatsächlich auf die begrenzte API beschränkt sind, und es wird keine Unterstützung für die Erstellung solcher Dateien in distutils hinzugefügt, da der distutils-Code eingefroren ist.

Implementierungsstrategie

Dieser PEP wird in einem Branch [2] implementiert, der es Benutzern ermöglicht zu prüfen, ob ihre Module der ABI entsprechen. Um zu vermeiden, dass Benutzer ihre Typdefinitionen neu schreiben müssen, wird ein Skript zur Konvertierung von C-Quellcode mit Typdefinitionen bereitgestellt [3].

Referenzen


Quelle: https://github.com/python/peps/blob/main/peps/pep-0384.rst

Zuletzt geändert: 2025-02-01 08:55:40 GMT