Introduction
L'interface du programmeur d'applications pour Python permet aux programmeurs C et C++
d'accéder à l'interpréteur Python à différents niveaux. L'API est également utilisable à partir
de C++, mais par souci de concision, elle est généralement appelée API Python/C. Il existe
deux raisons fondamentalement différentes d'utiliser l'API Python/C. La première raison est
d'écrire des modules d'extension à des fins spécifiques ; il s'agit de modules C qui étendent
l'interpréteur Python. Il s'agit probablement de l'utilisation la plus courante. La deuxième
raison est d'utiliser Python comme composant dans une application plus vaste ; cette
technique est généralement appelée intégration de Python dans une application.
L'écriture d'un module d'extension est un processus relativement bien compris, où une approche de
type « livre de recettes » fonctionne bien. Il existe plusieurs outils qui automatisent le processus
dans une certaine mesure. Bien que les gens aient intégré Python dans d'autres applications depuis
ses débuts, le processus d'intégration de Python est moins simple que l'écriture d'une extension.
De nombreuses fonctions API sont utiles, que vous intégriez ou étendiez Python ; de plus, la plupart
des applications qui intègrent Python devront également fournir une extension personnalisée. C'est
donc probablement une bonne idée de se familiariser avec l'écriture d'une extension avant de tenter
d'intégrer Python dans une application réelle.
Normes de codage
Si vous écrivez du code C pour inclusion dans CPython, vous devez suivre les directives et les
normes définies dansPEP 7. Ces directives s'appliquent quelle que soit la version de Python à
laquelle vous contribuez. Il n'est pas nécessaire de suivre ces conventions pour vos propres modules
d'extension tiers, à moins que vous n'envisagiez de les intégrer à Python.
Inclure les fichiers
Toutes les définitions de fonctions, de types et de macros nécessaires à l'utilisation de l'API
Python/C sont incluses dans votre code par la ligne suivante :
#define PY_SSIZE_T_CLEAN
#include <Python.h>
Cela implique l'inclusion des en-têtes standards
suivants : , , , <stdio.h>et <string.h>( <errno.h>si disponibles ).<limits.h><asser
t.h><stdlib.h>
Étant donné que Python peut définir certaines définitions de préprocesseur qui affectent les en-
têtes standard sur certains systèmes, vous devez les inclure Python.h avant que les en-têtes
standard ne soient inclus.
Il est recommandé de toujours définir PY_SSIZE_T_CLEAN avant d'inclure Python.h .
Voir Analyse des arguments et création de valeurs pour une description de cette macro.
Tous les noms visibles par l'utilisateur définis par Python.h (à l'exception de ceux définis par les en-
têtes standards inclus) ont l'un des préfixes Pyou _Py. Les noms commençant par _Pysont destinés
à un usage interne par l'implémentation Python et ne doivent pas être utilisés par les auteurs
d'extensions. Les noms des membres de la structure n'ont pas de préfixe réservé.
Note
Le code utilisateur ne doit jamais définir de noms commençant par Py ou _Py . Cela perturbe le
lecteur et compromet la portabilité du code utilisateur vers les futures versions de Python, qui
peuvent définir des noms supplémentaires commençant par l'un de ces préfixes.
Les fichiers d'en-tête sont généralement installés avec Python. Sous Unix, ils se trouvent dans les
répertoires et , où et sont définis par les paramètres correspondants du script de configuration de
Python et la version est . Sous Windows, les en-têtes sont installés dans , où est le répertoire
d'installation spécifié pour le programme
d'[Link]/include/pythonversion/exec_prefix/include/pythonve
rsion/prefixexec_prefix'%d.%d' % sys.version_info[:2]prefix/
includeprefix
Pour inclure les en-têtes, placez les deux répertoires (s'ils sont différents) sur le chemin de recherche
de votre compilateur pour les inclusions. Ne placez pas les répertoires parents sur le chemin de
recherche, puis utilisez ; cela échouera sur les builds multi-plateformes puisque les en-têtes
indépendants de la plate-forme sous incluent les en-têtes spécifiques à la plate-forme
de .#include <pythonX.Y/Python.h>prefixexec_prefix
Les utilisateurs de C++ doivent noter que même si l'API est entièrement définie à l'aide de C, les
fichiers d'en-tête déclarent correctement les points d'entrée comme étant . Par conséquent, il n'est
pas nécessaire de faire quoi que ce soit de spécial pour utiliser l'API à partir de C++.extern "C"
Macros utiles
Plusieurs macros utiles sont définies dans les fichiers d'en-tête Python. Beaucoup sont définies plus
près de l'endroit où elles sont utiles (par exemple Py_RETURN_NONE). D'autres, d'une utilité plus
générale, sont définies ici. Il ne s'agit pas nécessairement d'une liste complète.
PyMODINIT_FUNC
Déclarez une PyInitfonction d'initialisation de module d'extension. Le type de retour
de la fonction est PyObject * . La macro déclare toutes les déclarations de liaison
spéciales requises par la plateforme et, pour C++, déclare la fonction
comme .extern "C"
La fonction d'initialisation doit être nommée , où name est le nom du module et doit être
le seul élément non défini dans le fichier du module. Exemple :PyInit_namestatic
static struct PyModuleDef spam_module = {
PyModuleDef_HEAD_INIT,
.m_name = "spam",
...
};
PyMODINIT_FUNC
PyInit_spam(void)
{
return PyModule_Create(&spam_module);
}
Py_ABS ( x )
Renvoie la valeur absolue de x.
Ajouté dans la version 3.3.
Py_ALWAYS_INLINE
Demandez au compilateur de toujours intégrer une fonction statique en ligne. Le
compilateur peut l'ignorer et décider de ne pas intégrer la fonction en ligne.
Il peut être utilisé pour intégrer des fonctions statiques critiques en termes de
performances lors de la création de Python en mode débogage avec l'intégration de
fonctions désactivée. Par exemple, MSC désactive l'intégration de fonctions lors de la
création en mode débogage.
Marquer aveuglément une fonction statique en ligne avec Py_ALWAYS_INLINE peut
entraîner de moins bonnes performances (en raison d'une augmentation de la taille du
code par exemple). Le compilateur est généralement plus intelligent que le développeur
pour l'analyse coûts/bénéfices.
Si Python est construit en mode débogage (si la Py_DEBUG macro est définie),
la Py_ALWAYS_INLINEmacro ne fait rien.
Il doit être spécifié avant le type de retour de la fonction.
static inline Py_ALWAYS_INLINE int random(void) { return 4; }
Ajouté dans la version 3.11.
Py_CHARMASK ( c )
L'argument doit être un caractère ou un entier compris entre [-128, 127] ou [0, 255].
Cette macro renvoie cun cast en .unsigned char
Py_DEPRECATED ( version )
Utilisez ceci pour les déclarations obsolètes. La macro doit être placée avant le nom du
symbole.
Exemple:
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
Modifié dans la version 3.8 : le support MSVC a été ajouté.
Py_GETENV ( s )
Comme getenv(s), mais renvoie NULLsi -Ea été passé sur la ligne de commande
(voir PyConfig.use_environment).
Py_MAX ( x , y )
Renvoie la valeur maximale entre xet y.
Ajouté dans la version 3.3.
Py_MEMBER_SIZE ( type , membre )
Renvoie la taille d'une structure ( type) memberen octets.
Ajouté dans la version 3.6.
Py_MIN ( x , y )
Renvoie la valeur minimale entre xet y.
Ajouté dans la version 3.3.
Py_NO_INLINE
Désactiver l'inlining sur une fonction. Par exemple, cela réduit la consommation de la
pile C : utile sur les builds LTO+PGO qui intègrent beaucoup de code en ligne (voir bpo-
33720 ).
Usage:
Py_NO_INLINE static int random(void) { return 4; }
Ajouté dans la version 3.11.
Py_STRINGIFY ( x )
Convertir xen chaîne C. Par exemple, Py_STRINGIFY(123)renvoie "123".
Ajouté dans la version 3.4.
Py_UNREACHABLE ()
Utilisez cette option lorsque vous avez un chemin de code qui ne peut pas être atteint par
conception. Par exemple, dans la default:clause d'une switchinstruction pour
laquelle toutes les valeurs possibles sont couvertes par casedes instructions. Utilisez-la
dans les endroits où vous pourriez être tenté d'insérer
un appel assert(0)or .abort()
En mode release, la macro aide le compilateur à optimiser le code et évite un
avertissement concernant le code inaccessible. Par exemple, la macro est implémentée
avec __builtin_unreachable()sur GCC en mode release.
Une utilisation de Py_UNREACHABLE()est de suivre un appel à une fonction qui ne
renvoie jamais mais qui n'est pas déclarée _Py_NO_RETURN.
Si un chemin de code est un code très improbable mais peut être atteint dans des cas
exceptionnels, cette macro ne doit pas être utilisée. Par exemple, dans des conditions de
faible mémoire ou si un appel système renvoie une valeur hors de la plage attendue. Dans
ce cas, il est préférable de signaler l'erreur à l'appelant. Si l'erreur ne peut pas être
signalée à l'appelant, Py_FatalError()peut être utilisé.
Ajouté dans la version 3.7.
Py_UNUSED ( arg )
Utilisez ceci pour les arguments inutilisés dans une définition de fonction pour faire taire
les avertissements du compilateur.
Exemple : .int func(int a, int Py_UNUSED(b)) { return a; }
Ajouté dans la version 3.4.
PyDoc_STRVAR ( nom , str )
Crée une variable avec un nom namequi peut être utilisé dans les docstrings. Si Python
est construit sans docstrings, la valeur sera vide.
Utiliser PyDoc_STRVARpour les docstrings pour prendre en charge la création de
Python sans docstrings, comme spécifié dansPEP 7 .
Exemple:
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 )
Crée une docstring pour la chaîne d'entrée donnée ou une chaîne vide si les docstrings
sont désactivés.
À utiliser PyDoc_STRpour spécifier des docstrings afin de prendre en charge la création
de Python sans docstrings, comme spécifié dansPEP 7 .
Exemple:
static PyMethodDef pysqlite_row_methods[] = {
{"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
PyDoc_STR("Returns the keys of the row.")},
{NULL, NULL}
};
Objets, types et nombres de références
La plupart des fonctions API Python/C ont un ou plusieurs arguments ainsi qu'une valeur de retour
de type PyObject * . Ce type est un pointeur vers un type de données opaque représentant un objet
Python arbitraire. Étant donné que tous les types d'objets Python sont traités de la même manière
par le langage Python dans la plupart des situations (par exemple, les affectations, les règles de
portée et le passage d'arguments), il est tout à fait normal qu'ils soient représentés par un seul type
C. Presque tous les objets Python vivent sur le tas : vous ne déclarez jamais de variable automatique
ou statique de type PyObject, seules les variables pointeur de type PyObject * peuvent être
déclarées. La seule exception concerne les objets de type ; comme ceux-ci ne doivent jamais être
désalloués, ce sont généralement PyTypeObjectdes objets statiques.
Tous les objets Python (même les entiers Python) ont un type et un nombre de références . Le type
d'un objet détermine de quel type d'objet il s'agit (par exemple, un entier, une liste ou une fonction
définie par l'utilisateur ; il en existe bien d'autres, comme expliqué dans La hiérarchie des types
standard ). Pour chacun des types bien connus, il existe une macro pour vérifier si un objet est de ce
type ; par exemple, PyList_Check(a)est vrai si (et seulement si) l'objet pointé par a est une
liste Python.
Nombre de références
Le nombre de références est important car les ordinateurs d'aujourd'hui ont une taille de mémoire
finie (et souvent très limitée) ; il compte le nombre d'emplacements différents qui ont une référence
forte à un objet. Un tel emplacement peut être un autre objet, ou une variable C globale (ou
statique), ou une variable locale dans une fonction C. Lorsque la dernière référence forte à un objet
est libérée (c'est-à-dire que son nombre de références devient nul), l'objet est libéré. S'il contient des
références à d'autres objets, ces références sont libérées. Ces autres objets peuvent être libérés à leur
tour, s'il n'y a plus de références à eux, et ainsi de suite. (Il y a un problème évident avec les objets
qui se référencent les uns les autres ici ; pour l'instant, la solution est « ne faites pas ça ».)
Les compteurs de références sont toujours manipulés de manière explicite. La méthode normale
consiste à utiliser la macro Py_INCREF()pour prendre une nouvelle référence à un objet (c'est-à-
dire incrémenter son compteur de références de un) et Py_DECREF()pour libérer cette référence
(c'est-à-dire décrémenter le compteur de références de un). La Py_DECREF()macro est
considérablement plus complexe que celle d'incref, car elle doit vérifier si le compteur de références
devient nul, puis provoquer l'appel du désallocateur de l'objet. Le désallocateur est un pointeur de
fonction contenu dans la structure de type de l'objet. Le désallocateur spécifique au type se charge
de libérer les références pour d'autres objets contenus dans l'objet s'il s'agit d'un type d'objet
composé, comme une liste, ainsi que d'effectuer toute finalisation supplémentaire nécessaire. Il n'y a
aucune chance que le compteur de références puisse déborder ; au moins autant de bits sont utilisés
pour contenir le compteur de références qu'il y a d'emplacements mémoire distincts dans la
mémoire virtuelle (en supposant que ). Ainsi, l'incrémentation du compteur de références est une
opération [Link](Py_ssize_t) >= sizeof(void*)
Il n'est pas nécessaire de conserver une référence forte (c'est-à-dire d'incrémenter le nombre de
références) pour chaque variable locale qui contient un pointeur vers un objet. En théorie, le nombre
de références de l'objet augmente d'une unité lorsque la variable pointe vers lui et il diminue d'une
unité lorsque la variable sort de la portée. Cependant, ces deux s'annulent, donc à la fin le nombre
de références n'a pas changé. La seule vraie raison d'utiliser le nombre de références est d'empêcher
que l'objet soit désalloué tant que notre variable pointe vers lui. Si nous savons qu'il existe au moins
une autre référence à l'objet qui vit au moins aussi longtemps que notre variable, il n'est pas
nécessaire de prendre une nouvelle référence forte (c'est-à-dire d'incrémenter le nombre de
références) temporairement. Une situation importante où cela se produit est dans les objets qui sont
passés comme arguments à des fonctions C dans un module d'extension qui sont appelés depuis
Python ; le mécanisme d'appel garantit de conserver une référence à chaque argument pendant la
durée de l'appel.
Cependant, un piège courant consiste à extraire un objet d'une liste et à le conserver pendant un
certain temps sans prendre de nouvelle référence. Une autre opération pourrait éventuellement
supprimer l'objet de la liste, libérant ainsi cette référence et éventuellement le désallouant. Le
véritable danger est que des opérations apparemment innocentes puissent invoquer du code Python
arbitraire qui pourrait faire cela ; il existe un chemin de code qui permet de renvoyer le contrôle à
l'utilisateur à partir d'un Py_DECREF(), donc presque toutes les opérations sont potentiellement
dangereuses.
Une approche sûre consiste à toujours utiliser les opérations génériques (fonctions dont le nom
commence par PyObject_, PyNumber_, PySequence_ou PyMapping_). Ces opérations
créent toujours une nouvelle référence forte (c'est-à-dire incrémentent le nombre de références) de
l'objet qu'elles renvoient. Cela laisse à l'appelant la responsabilité d'appeler Py_DECREF()lorsqu'il
a terminé avec le résultat ; cela devient rapidement une seconde nature.
Détails du nombre de références
Le comportement du comptage de références des fonctions dans l'API Python/C s'explique mieux
en termes de propriété des références . La propriété concerne les références, jamais les objets (les
objets ne sont pas possédés : ils sont toujours partagés). « Posséder une référence » signifie être
responsable de l'appel de Py_DECREF sur celle-ci lorsque la référence n'est plus nécessaire. La
propriété peut également être transférée, ce qui signifie que le code qui reçoit la propriété de la
référence devient alors responsable de la libérer éventuellement en
appelant Py_DECREF()ou Py_XDECREF() lorsqu'elle n'est plus nécessaire, ou en transmettant
cette responsabilité (généralement à son appelant). Lorsqu'une fonction transmet la propriété d'une
référence à son appelant, on dit que l'appelant reçoit une nouvelle référence. Lorsqu'aucune
propriété n'est transférée, on dit que l'appelant emprunte la référence. Rien ne doit être fait pour
une référence empruntée .
À l'inverse, lorsqu'une fonction appelante transmet une référence à un objet, il existe deux
possibilités : la fonction vole une référence à l'objet ou non. Le vol d'une référence signifie que
lorsque vous transmettez une référence à une fonction, cette fonction suppose qu'elle possède
désormais cette référence et que vous n'en êtes plus responsable.
Peu de fonctions volent des références ; les deux exceptions notables
sont PyList_SetItem()et PyTuple_SetItem(), qui volent une référence à l'élément (mais
pas au tuple ou à la liste dans laquelle l'élément est placé !). Ces fonctions ont été conçues pour
voler une référence en raison d'un idiome courant pour remplir un tuple ou une liste avec des objets
nouvellement créés ; par exemple, le code pour créer le tuple pourrait ressembler à ceci (en oubliant
la gestion des erreurs pour le moment ; une meilleure façon de coder ceci est présentée ci-dessous) :
(1, 2, "three")
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"));
Ici, PyLong_FromLong()renvoie une nouvelle référence qui est immédiatement volée
par PyTuple_SetItem(). Lorsque vous souhaitez continuer à utiliser un objet même si la
référence à celui-ci est volée, utilisez Py_INCREF()pour récupérer une autre référence avant
d'appeler la fonction de vol de référence.
D'ailleurs, PyTuple_SetItem()c'est la seule façon de définir des éléments de
tuple ; PySequence_SetItem()et PyObject_SetItem()refusez de le faire car les tuples
sont un type de données immuable. Vous ne devez l'utiliser que PyTuple_SetItem()pour les
tuples que vous créez vous-même.
Un code équivalent pour remplir une liste peut être écrit en
utilisant PyList_New() et PyList_SetItem().
Cependant, dans la pratique, vous utiliserez rarement ces méthodes de création et de remplissage
d'un tuple ou d'une liste. Il existe une fonction générique, Py_BuildValue(), qui peut créer la
plupart des objets courants à partir de valeurs C, dirigées par une chaîne de format . Par exemple,
les deux blocs de code ci-dessus pourraient être remplacés par ce qui suit (qui s'occupe également
de la vérification des erreurs) :
PyObject *tuple, *list;
tuple = Py_BuildValue("(iis)", 1, 2, "three");
list = Py_BuildValue("[iis]", 1, 2, "three");
Il est beaucoup plus courant d'utiliser PyObject_SetItem()and friends avec des éléments dont
vous empruntez seulement les références, comme les arguments qui ont été passés à la fonction que
vous écrivez. Dans ce cas, leur comportement vis-à-vis des références est beaucoup plus sain,
puisque vous n'avez pas besoin de prendre une nouvelle référence juste pour pouvoir la donner (« la
faire voler »). Par exemple, cette fonction définit tous les éléments d'une liste (en fait, toute
séquence mutable) sur un élément donné :
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;
}
La situation est légèrement différente pour les valeurs de retour de fonction. Bien que le passage
d'une référence à la plupart des fonctions ne modifie pas vos responsabilités de propriété pour cette
référence, de nombreuses fonctions qui renvoient une référence à un objet vous confèrent la
propriété de la référence. La raison est simple : dans de nombreux cas, l'objet renvoyé est créé à la
volée et la référence que vous obtenez est la seule référence à l'objet. Par conséquent, les fonctions
génériques qui renvoient des références d'objet,
comme PyObject_GetItem()et PySequence_GetItem(), renvoient toujours une nouvelle
référence (l'appelant devient le propriétaire de la référence).
Il est important de comprendre que le fait de posséder une référence renvoyée par une fonction
dépend uniquement de la fonction que vous appelez — le plumage (le type de l'objet passé en
argument à la fonction) n'y entre pas en compte ! Ainsi, si vous extrayez un élément d'une liste en
utilisant PyList_GetItem(), vous ne possédez pas la référence — mais si vous obtenez le
même élément de la même liste en utilisant PySequence_GetItem()(qui prend exactement les
mêmes arguments), vous possédez une référence à l'objet renvoyé.
Voici un exemple de la manière dont vous pourriez écrire une fonction qui calcule la somme des
éléments d'une liste d'entiers ; une fois en utilisant PyList_GetItem(), et une fois en
utilisant 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;
}
Types
Il existe peu d'autres types de données qui jouent un rôle significatif dans l'API Python/C ; la
plupart sont des types C simples tels que int , long , double et char * . Quelques types de structure
sont utilisés pour décrire des tables statiques utilisées pour lister les fonctions exportées par un
module ou les attributs de données d'un nouveau type d'objet, et un autre est utilisé pour décrire la
valeur d'un nombre complexe. Ceux-ci seront abordés avec les fonctions qui les utilisent.
tapez Py_ssize_t
Une partie de l' ABI stable .
Un type intégral signé tel que . C99 ne définit pas directement une telle chose (size_t est
un type intégral non signé).
Voirsizeof(Py_ssize_t) == sizeof(size_t)PEP 353 pour plus de
détails.PY_SSIZE_T_MAXest la plus grande valeur positive de typePy_ssize_t.
Exceptions
Le programmeur Python n'a besoin de gérer les exceptions que si une gestion spécifique des erreurs
est requise ; les exceptions non gérées sont automatiquement propagées à l'appelant, puis à
l'appelant de l'appelant, et ainsi de suite, jusqu'à ce qu'elles atteignent l'interpréteur de niveau
supérieur, où elles sont signalées à l'utilisateur accompagnées d'une trace de pile.
Pour les programmeurs C, cependant, la vérification des erreurs doit toujours être explicite. Toutes
les fonctions de l'API Python/C peuvent générer des exceptions, sauf indication contraire explicite
dans la documentation d'une fonction. En général, lorsqu'une fonction rencontre une erreur, elle
définit une exception, supprime toutes les références d'objet qu'elle possède et renvoie un indicateur
d'erreur. Sauf indication contraire, cet indicateur est soit NULLou -1, selon le type de retour de la
fonction. Quelques fonctions renvoient un résultat booléen true/false, false indiquant une erreur.
Très peu de fonctions ne renvoient aucun indicateur d'erreur explicite ou ont une valeur de retour
ambiguë, et nécessitent un test explicite des erreurs avec PyErr_Occurred(). Ces exceptions
sont toujours explicitement documentées.
L'état d'exception est conservé dans le stockage par thread (ce qui équivaut à utiliser le stockage
global dans une application non threadée). Un thread peut être dans l'un des deux états suivants :
une exception s'est produite ou non. La fonction PyErr_Occurred()peut être utilisée pour
vérifier cela : elle renvoie une référence empruntée à l'objet de type d'exception lorsqu'une
exception s'est produite et NULLdans les autres cas. Il existe un certain nombre de fonctions pour
définir l'état d'exception : PyErr_SetString()est la fonction la plus courante (mais pas la plus
générale) pour définir l'état d'exception et PyErr_Clear()efface l'état d'exception.
L'état d'exception complet se compose de trois objets (qui peuvent tous être NULL) : le type
d'exception, la valeur d'exception correspondante et la traceback. Ceux-ci ont la même signification
que le résultat Python de sys.exc_info(); cependant, ils ne sont pas les mêmes : les objets
Python représentent la dernière exception gérée par une instruction Python try… except, tandis
que l'état d'exception de niveau C n'existe que pendant qu'une exception est transmise entre des
fonctions C jusqu'à ce qu'elle atteigne la boucle principale de l'interpréteur de bytecode Python, qui
se charge de la transférer à sys.exc_info()et amis.
Notez qu'à partir de Python 1.5, la méthode préférée et sécurisée pour accéder à l'état d'exception à
partir du code Python consiste à appeler la fonction sys.exc_info(), qui renvoie l'état
d'exception par thread pour le code Python. De plus, la sémantique des deux méthodes d'accès à
l'état d'exception a changé de sorte qu'une fonction qui intercepte une exception enregistre et
restaure l'état d'exception de son thread afin de préserver l'état d'exception de son appelant. Cela
évite les bogues courants dans le code de gestion des exceptions causés par une fonction
d'apparence innocente qui écrase l'exception en cours de gestion ; cela réduit également l'extension
de durée de vie souvent indésirable pour les objets référencés par les cadres de pile dans la trace de
retour.
En règle générale, une fonction qui appelle une autre fonction pour effectuer une tâche doit vérifier
si la fonction appelée a déclenché une exception et, si tel est le cas, transmettre l'état de l'exception
à son appelant. Elle doit ignorer toutes les références d'objet qu'elle possède et renvoyer un
indicateur d'erreur, mais elle ne doit pas définir une autre exception, car cela écraserait l'exception
qui vient d'être déclenchée et perdrait des informations importantes sur la cause exacte de l'erreur.
Un exemple simple de détection d'exceptions et de leur transmission est illustré dans
l' sum_sequence()exemple ci-dessus. Il se trouve que cet exemple n'a pas besoin de nettoyer les
références possédées lorsqu'il détecte une erreur. L'exemple de fonction suivant montre un
nettoyage d'erreur. Tout d'abord, pour vous rappeler pourquoi vous aimez Python, nous vous
montrons le code Python équivalent :
def incr_item(dict, key):
try:
item = dict[key]
except KeyError:
item = 0
dict[key] = item + 1
Voici le code C correspondant, dans toute sa splendeur :
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 */
}
Cet exemple représente une utilisation approuvée de l' gotoinstruction en C! Il illustre l'utilisation
de PyErr_ExceptionMatches()et PyErr_Clear()pour gérer des exceptions spécifiques,
et l'utilisation de Py_XDECREF()pour éliminer les références possédées qui peuvent
être NULL(notez le 'X'dans le nom ; Py_DECREF()planterait en cas de confrontation avec
une NULLréférence). Il est important que les variables utilisées pour contenir les références
possédées soient initialisées à NULLpour que cela fonctionne ; de même, la valeur de retour
proposée est initialisée à -1(échec) et définie uniquement sur succès après que l'appel final effectué
ait réussi.
Intégration de Python
La seule tâche importante dont seuls les intégrateurs (par opposition aux rédacteurs d'extensions) de
l'interpréteur Python doivent se soucier est l'initialisation, et éventuellement la finalisation, de
l'interpréteur Python. La plupart des fonctionnalités de l'interpréteur ne peuvent être utilisées qu'une
fois l'interpréteur initialisé.
La fonction d'initialisation de base est Py_Initialize(). Elle initialise la table des modules
chargés et crée les modules fondamentaux builtins, __main__, et sys. Elle initialise
également le chemin de recherche du module ( [Link]).
Py_Initialize()ne définit pas la « liste d'arguments de script » ( [Link]). Si cette
variable est nécessaire au code Python qui sera exécuté ultérieurement, les
paramètres [Link] PyConfig.parse_argvdoivent être définis :
voir Configuration d'initialisation Python .
Sur la plupart des systèmes (en particulier sous Unix et Windows, bien que les détails soient
légèrement différents), Py_Initialize()calcule le chemin de recherche du module en fonction
de sa meilleure estimation de l'emplacement de l'exécutable de l'interpréteur Python standard, en
supposant que la bibliothèque Python se trouve à un emplacement fixe par rapport à l'exécutable de
l'interpréteur Python. En particulier, il recherche un répertoire nommé par rapport au répertoire
parent où l'exécutable nommé se trouve sur le chemin de recherche de la commande shell (la
variable d'environnementlib/[Link]).
Par exemple, si l'exécutable Python se trouve dans /usr/local/bin/python, il supposera que
les bibliothèques se trouvent dans . (En fait, ce chemin particulier est également l'emplacement de «
secours », utilisé lorsqu'aucun fichier exécutable nommé n'est trouvé le long
de/usr/local/lib/[Link].) L'utilisateur peut remplacer ce
comportement en définissant la variable d'environnementPYTHONHOME, ou insérez des répertoires
supplémentaires devant le chemin standard en définissantPYTHONPATH.
L'application d'intégration peut orienter la recherche en définissant avant d'appeler . Notez
que PyConfig.program_name Py_InitializeFromConfig()PYTHONHOMEremplace
toujours cela etPYTHONPATHest toujours inséré devant le chemin standard. Une application qui
nécessite un contrôle total doit fournir sa propre implémentation
de Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()et Py_GetProgramFull
Path()(tous définis dans Modules/getpath.c).
Parfois, il est souhaitable de « désinitialiser » Python. Par exemple, l'application peut vouloir tout
recommencer (effectuer un autre appel à Py_Initialize()) ou l'application en a simplement
fini avec son utilisation de Python et souhaite libérer la mémoire allouée par Python. Cela peut être
accompli en appelant Py_FinalizeEx(). La fonction Py_IsInitialized()renvoie true si
Python est actuellement dans l'état initialisé. Plus d'informations sur ces fonctions sont données
dans un chapitre ultérieur. Notez que Py_FinalizeEx() ne libère pas toute la mémoire allouée
par l'interpréteur Python, par exemple la mémoire allouée par les modules d'extension ne peut
actuellement pas être libérée.
Builds de débogage
Python peut être construit avec plusieurs macros pour permettre des vérifications supplémentaires
de l'interpréteur et des modules d'extension. Ces vérifications ont tendance à ajouter une charge
importante au runtime, elles ne sont donc pas activées par défaut.
Une liste complète des différents types de builds de débogage se trouve dans le
fichier Misc/[Link] la distribution source de Python. Des builds sont
disponibles qui prennent en charge le traçage des comptages de références, le débogage de
l'allocateur de mémoire ou le profilage de bas niveau de la boucle d'interprétation principale. Seules
les builds les plus fréquemment utilisées seront décrites dans le reste de cette section.
Py_DEBUG
La compilation de l'interpréteur avec la Py_DEBUGmacro définie produit ce que l'on entend
généralement par une version de débogage de Python . Py_DEBUGest activée dans la version Unix
en ajoutant --with-pydebugà la ./configurecommande. Elle est également impliquée par
la présence de la macro non spécifique à Python _DEBUG. Lorsque Py_DEBUGest activée dans la
version Unix, l'optimisation du compilateur est désactivée.
En plus du débogage du nombre de références décrit ci-dessous, des vérifications supplémentaires
sont effectuées, voir Python Debug Build .
La définition Py_TRACE_REFSpermet le traçage des références (voir le ). Une fois définie, une
liste circulaire doublement chaînée d'objets actifs est maintenue en ajoutant deux champs
supplémentaires à chaque . Les allocations totales sont également suivies. À la sortie, toutes les
références existantes sont imprimées. (En mode interactif, cela se produit après chaque instruction
exécutée par l'interpréteur.)configure --with-trace-refs optionPyObject
Veuillez vous référer Misc/[Link]à la distribution source Python pour des
informations plus détaillées.