1. Utöka Python med C eller C++

Det är ganska enkelt att lägga till nya inbyggda moduler till Python, om du vet hur man programmerar i C. Sådana extension modules kan göra två saker som inte kan göras direkt i Python: de kan implementera nya inbyggda objekttyper, och de kan anropa C-biblioteksfunktioner och systemanrop.

För att stödja tillägg definierar Python API (Application Programmers Interface) en uppsättning funktioner, makron och variabler som ger tillgång till de flesta aspekter av Pythons runtime-system. Python API införlivas i en C-källfil genom att inkludera rubriken "Python.h".

Sammanställningen av en tilläggsmodul beror på hur den ska användas och på hur systemet är uppbyggt; mer information om detta finns i senare kapitel.

Anteckning

Gränssnittet för C-tillägg är specifikt för CPython, och tilläggsmoduler fungerar inte på andra Python-implementeringar. I många fall är det möjligt att undvika att skriva C-tillägg och bevara portabiliteten till andra implementationer. Om ditt användningsområde till exempel är att anropa C-biblioteksfunktioner eller systemanrop, bör du överväga att använda ctypes-modulen eller biblioteket cffi i stället för att skriva egen C-kod. Med dessa moduler kan du skriva Python-kod för gränssnitt med C-kod och de är mer portabla mellan olika implementationer av Python än att skriva och kompilera en C-tilläggsmodul.

1.1. Ett enkelt exempel

Låt oss skapa en tilläggsmodul som heter spam (Monty Python-fansens favoritmat…) och låt oss säga att vi vill skapa ett Python-gränssnitt till C-bibliotekets funktion system() [1]. Denna funktion tar en nollavslutad teckensträng som argument och returnerar ett heltal. Vi vill att denna funktion ska kunna anropas från Python enligt följande:

>>> import spam
>>> status = spam.system("ls -l")

Börja med att skapa en fil spammodule.c. (Historiskt sett, om en modul heter spam, heter C-filen som innehåller dess implementation spammodule.c; om modulnamnet är mycket långt, som spammify, kan modulnamnet bara vara spammify.c)

De två första raderna i vår fil kan vara:

#definiera PY_SSIZE_T_CLEAN
#inkludera <Python.h>

som hämtar Python API (du kan lägga till en kommentar som beskriver syftet med modulen och ett upphovsrättsmeddelande om du vill).

Anteckning

Eftersom Python kan definiera vissa preprocessordefinitioner som påverkar standardrubrikerna på vissa system, måste du inkludera Python.h innan några standardrubriker inkluderas.

#define PY_SSIZE_T_CLEAN användes för att indikera att Py_ssize_t skulle användas i vissa API:er istället för int. Det är inte nödvändigt sedan Python 3.13, men vi behåller det här för bakåtkompatibilitet. Se Strängar och buffertar för en beskrivning av detta makro.

Alla användarsynliga symboler som definieras av Python.h har prefixet Py eller PY, utom de som definieras i standardhuvudfiler. För enkelhetens skull, och eftersom de används flitigt av Python-tolken, innehåller "Python.h" några standardheaderfiler: <stdio.h>, <string.h>, <errno.h> och <stdlib.h>. Om den senare huvudfilen inte finns på ditt system, deklarerar den funktionerna malloc(), free() och realloc() direkt.

Nästa sak vi lägger till i vår modulfil är den C-funktion som kommer att anropas när Python-uttrycket spam.system(string) utvärderas (vi ska snart se hur den kommer att anropas):

static PyObject *
spam_system(PyObject *self, PyObject *args)
{
    const char *command;
    int sts;

    if (!PyArg_ParseTuple(args, "s", &command))
        return NULL;
    sts = system(command);
    return PyLong_FromLong(sts);
}

Det finns en enkel översättning från argumentlistan i Python (t.ex. det enkla uttrycket "ls -l") till de argument som skickas till C-funktionen. C-funktionen har alltid två argument, konventionellt benämnda self och args.

Argumentet self pekar på modulobjektet för funktioner på modulnivå; för en metod skulle det peka på objektinstansen.

Argumentet args kommer att vara en pekare till ett Python-tuple-objekt som innehåller argumenten. Varje post i tupeln motsvarar ett argument i anropets argumentlista. Argumenten är Python-objekt — för att kunna göra något med dem i vår C-funktion måste vi konvertera dem till C-värden. Funktionen PyArg_ParseTuple() i Python API kontrollerar argumenttyperna och konverterar dem till C-värden. Den använder en mallsträng för att bestämma de nödvändiga typerna av argumenten samt typerna av de C-variabler som de konverterade värdena ska lagras i. Mer om detta senare.

PyArg_ParseTuple() returnerar true (icke-noll) om alla argument har rätt typ och dess komponenter har lagrats i de variabler vars adresser skickas. Den returnerar false (noll) om en ogiltig argumentlista har skickats. I det senare fallet ger den också upphov till ett lämpligt undantag så att den anropande funktionen kan returnera NULL omedelbart (som vi såg i exemplet).

1.2. Intermezzo: Fel och undantag

En viktig konvention i hela Python-tolken är följande: när en funktion misslyckas ska den sätta ett undantagstillstånd och returnera ett felvärde (vanligtvis -1 eller en NULL-pekare). Undantagsinformation lagras i tre medlemmar av tolkens trådstatus. Dessa är NULL om det inte finns något undantag. I annat fall är de C-motsvarigheterna till medlemmarna i Python-tuplen som returneras av sys.exc_info(). Dessa är undantagstyp, undantagsinstans och ett spårningsobjekt. Det är viktigt att känna till dem för att förstå hur fel vidarebefordras.

Python API definierar ett antal funktioner för att ställa in olika typer av undantag.

Den vanligaste är PyErr_SetString(). Dess argument är ett undantagsobjekt och en C-sträng. Undantagsobjektet är vanligtvis ett fördefinierat objekt som PyExc_ZeroDivisionError. C-strängen anger orsaken till felet och konverteras till ett Python-strängobjekt och lagras som det ”associerade värdet” för undantaget.

En annan användbar funktion är PyErr_SetFromErrno(), som bara tar ett undantagsargument och konstruerar det associerade värdet genom inspektion av den globala variabeln errno. Den mest allmänna funktionen är PyErr_SetObject(), som tar två objektargument, undantaget och dess associerade värde. Du behöver inte Py_INCREF() de objekt som skickas till någon av dessa funktioner.

Du kan testa icke-destruktivt om ett undantag har ställts in med PyErr_Occurred(). Detta returnerar det aktuella undantagsobjektet, eller NULL om inget undantag har inträffat. Du behöver normalt inte anropa PyErr_Occurred() för att se om ett fel inträffade i ett funktionsanrop, eftersom du bör kunna se det från returvärdet.

När en funktion f som anropar en annan funktion g upptäcker att den senare misslyckas, bör f själv returnera ett felvärde (vanligtvis NULL eller -1). Den ska inte anropa någon av funktionerna PyErr_* — en sådan har redan anropats av g. f:s anropare ska sedan också returnera en felindikation till sin anropare, återigen utan att anropa PyErr_*, och så vidare — den mest detaljerade orsaken till felet rapporterades redan av den funktion som först upptäckte det. När felet når Python-tolkens huvudslinga avbryter denna den Python-kod som för närvarande körs och försöker hitta en undantagshanterare som specificerats av Python-programmeraren.

(Det finns situationer där en modul faktiskt kan ge ett mer detaljerat felmeddelande genom att anropa en annan PyErr_*-funktion, och i sådana fall är det bra att göra det. Som en allmän regel är detta dock inte nödvändigt och kan leda till att information om orsaken till felet går förlorad: de flesta operationer kan misslyckas av olika skäl)

Om du vill ignorera ett undantag som skapats av ett funktionsanrop som misslyckades måste undantagsvillkoret rensas explicit genom att anropa PyErr_Clear(). Den enda gången C-kod bör anropa PyErr_Clear() är om den inte vill skicka felet vidare till tolken utan vill hantera det helt själv (eventuellt genom att prova något annat eller låtsas att inget gick fel).

Varje misslyckat anrop av malloc() måste förvandlas till ett undantag — den som direkt anropar malloc() (eller realloc()) måste anropa PyErr_NoMemory() och själv returnera en felindikator. Alla objektskapande funktioner (t.ex. PyLong_FromLong()) gör redan detta, så denna anmärkning är bara relevant för dem som anropar malloc() direkt.

Observera också att, med det viktiga undantaget PyArg_ParseTuple() och vänner, funktioner som returnerar en heltalsstatus vanligtvis returnerar ett positivt värde eller noll för framgång och -1 för misslyckande, som Unix systemanrop.

Slutligen, var noga med att rensa bort skräp (genom att göra Py_XDECREF() eller Py_DECREF() anrop för objekt som du redan har skapat) när du returnerar en felindikator!

Valet av vilket undantag som ska tas upp är helt och hållet ditt. Det finns fördeklarerade C-objekt som motsvarar alla inbyggda Python-undantag, till exempel PyExc_ZeroDivisionError, som du kan använda direkt. Naturligtvis bör du välja undantag klokt — använd inte PyExc_TypeError för att betyda att en fil inte kunde öppnas (det borde förmodligen vara PyExc_OSError). Om något är fel med argumentlistan ger funktionen PyArg_ParseTuple() vanligtvis PyExc_TypeError. Om du har ett argument vars värde måste ligga inom ett visst intervall eller måste uppfylla andra villkor, är PyExc_ValueError lämplig.

Du kan också definiera ett nytt undantag som är unikt för din modul. Det enklaste sättet att göra detta är att deklarera en statisk global objektvariabel i början av filen:

statiskt PyObject *SpamError = NULL;

och initiera den genom att anropa PyErr_NewException() i modulens Py_mod_exec-funktion (spam_module_exec()):

SpamError = PyErr_NewException("spam.error", NULL, NULL);

Eftersom SpamError är en global variabel kommer den att skrivas över varje gång modulen initieras på nytt, när funktionen Py_mod_exec anropas.

För tillfället undviker vi problemet: vi blockerar upprepade initialiseringar genom att skapa ett ImportError:

static PyObject *SpamError = NULL;

static int
spam_module_exec(PyObject *m)
{
    if (SpamError != NULL) {
        PyErr_SetString(PyExc_ImportError,
                        "cannot initialize spam module more than once");
        return -1;
    }
    SpamError = PyErr_NewException("spam.error", NULL, NULL);
    if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) {
        return -1;
    }

    return 0;
}

static PyModuleDef_Slot spam_module_slots[] = {
    {Py_mod_exec, spam_module_exec},
    {0, NULL}
};

static struct PyModuleDef spam_module = {
    .m_base = PyModuleDef_HEAD_INIT,
    .m_name = "spam",
    .m_size = 0,  // non-negative
    .m_slots = spam_module_slots,
};

PyMODINIT_FUNC
PyInit_spam(void)
{
    return PyModuleDef_Init(&spam_module);
}

Observera att Python-namnet för undantagsobjektet är spam.error. Funktionen PyErr_NewException() kan skapa en klass med basklassen Exception (om inte en annan klass anges istället för NULL), som beskrivs i Inbyggda undantag.

Notera också att variabeln SpamError behåller en referens till den nyskapade undantagsklassen; detta är avsiktligt! Eftersom undantaget kan tas bort från modulen av extern kod, behövs en ägd referens till klassen för att säkerställa att den inte kasseras, vilket gör att SpamError blir en dinglande pekare. Om den blir en dinglande pekare kan C-kod som väcker undantaget orsaka en kärndump eller andra oavsiktliga bieffekter.

För tillfället saknas Py_DECREF()-anropet för att ta bort denna referens. Även när Python-tolken stängs av kommer den globala SpamError-variabeln inte att samlas in. Den kommer att ”läcka”. Vi har dock försäkrat oss om att detta kommer att ske högst en gång per process.

Vi diskuterar användningen av PyMODINIT_FUNC som funktionens returtyp senare i detta exempel.

Undantaget spam.error kan skapas i din tilläggsmodul med hjälp av ett anrop till PyErr_SetString() enligt nedan:

static PyObject *
spam_system(PyObject *self, PyObject *args)
{
    const char *command;
    int sts;

    if (!PyArg_ParseTuple(args, "s", &command))
        return NULL;
    sts = system(command);
    if (sts < 0) {
        PyErr_SetString(SpamError, "System command failed");
        return NULL;
    }
    return PyLong_FromLong(sts);
}

1.3. Tillbaka till exemplet

Om vi går tillbaka till vår exempelfunktion bör du nu kunna förstå detta uttalande:

if (!PyArg_ParseTuple(args, "s", &kommando))
    returnera NULL;

Den returnerar NULL (felindikatorn för funktioner som returnerar objektpekare) om ett fel upptäcks i argumentlistan och förlitar sig på undantaget som anges av PyArg_ParseTuple(). Annars har argumentets strängvärde kopierats till den lokala variabeln command. Detta är en pekartilldelning och det är inte meningen att du ska ändra strängen som den pekar på (så i Standard C bör variabeln command korrekt deklareras som const char *command).

Nästa sats är ett anrop till Unix-funktionen system() och skickar den strängen som vi just fick från PyArg_ParseTuple():

sts = system(kommando);

Vår funktion spam.system() måste returnera värdet av sts som ett Python-objekt. Detta görs med hjälp av funktionen PyLong_FromLong().

return PyLong_FromLong(m);

I det här fallet kommer det att returnera ett heltalsobjekt. (Ja, även heltal är objekt på heapen i Python!)

Om du har en C-funktion som inte returnerar något användbart argument (en funktion som returnerar void), måste motsvarande Python-funktion returnera None. Du behöver detta idiom för att göra det (som implementeras av Py_RETURN_NONE macro):

Py_INCREF(Py_None);
return Py_None;

Py_None är C-namnet för det speciella Python-objektet None. Det är ett äkta Python-objekt snarare än en NULL-pekare, som betyder ”fel” i de flesta sammanhang, som vi har sett.

1.4. Modulens metodtabell och initialiseringsfunktion

Jag lovade att visa hur spam_system() anropas från Python-program. Först måste vi lista dess namn och adress i en ”metodtabell”:

statisk PyMethodDef spam_methods[] = {
    ...
    {"system", spam_system, METH_VARARGS,
     "Utför ett shell-kommando."},
    ...
    {NULL, NULL, 0, NULL}        /* Sentinel */
};

Lägg märke till den tredje posten (METH_VARARGS). Detta är en flagga som talar om för tolken vilken anropskonvention som ska användas för C-funktionen. Den bör normalt alltid vara METH_VARARGS eller METH_VARARGS | METH_KEYWORDS; ett värde på 0 betyder att en föråldrad variant av PyArg_ParseTuple() används.

När endast METH_VARARGS används bör funktionen förvänta sig att parametrarna på Python-nivå skickas in som en tupel som kan tolkas via PyArg_ParseTuple(); mer information om denna funktion finns nedan.

Bit METH_KEYWORDS kan sättas i det tredje fältet om nyckelordsargument skall skickas till funktionen. I detta fall bör C-funktionen acceptera en tredje PyObject * parameter som kommer att vara en ordbok med nyckelord. Använd PyArg_ParseTupleAndKeywords() för att analysera argumenten till en sådan funktion.

Metodtabellen måste refereras till i modulens definitionsstruktur:

static struct PyModuleDef spam_module = {
    ...
    .m_methods = spam_methods,
    ...
};

Denna struktur måste i sin tur skickas till tolken i modulens initialiseringsfunktion. Initialiseringsfunktionen måste heta PyInit_name(), där name är modulens namn, och bör vara det enda icke-statiska objektet som definieras i modulfilen:

PyMODINIT_FUNC
PyInit_spam(void)
{
    return PyModuleDef_Init(&spam_module);
}

Observera att PyMODINIT_FUNC deklarerar funktionen som PyObject * returtyp, deklarerar eventuella speciella länkdeklarationer som krävs av plattformen, och för C++ deklarerar funktionen som extern "C".

PyInit_spam() anropas när varje tolk importerar sin modul spam för första gången. (Se nedan för kommentarer om inbäddning av Python.) En pekare till moduldefinitionen måste returneras via PyModuleDef_Init(), så att importmaskineriet kan skapa modulen och lagra den i sys.modules.

Vid inbäddning av Python anropas inte funktionen PyInit_spam() automatiskt om det inte finns en post i tabellen PyImport_Inittab. För att lägga till modulen i initialiseringstabellen, använd PyImport_AppendInittab(), eventuellt följt av en import av modulen:

#define PY_SSIZE_T_CLEAN
#include <Python.h>

int
main(int argc, char *argv[])
{
    PyStatus status;
    PyConfig config;
    PyConfig_InitPythonConfig(&config);

    /* Add a built-in module, before Py_Initialize */
    if (PyImport_AppendInittab("spam", PyInit_spam) == -1) {
        fprintf(stderr, "Error: could not extend in-built modules table\n");
        exit(1);
    }

    /* Pass argv[0] to the Python interpreter */
    status = PyConfig_SetBytesString(&config, &config.program_name, argv[0]);
    if (PyStatus_Exception(status)) {
        goto exception;
    }

    /* Initialize the Python interpreter.  Required.
       If this step fails, it will be a fatal error. */
    status = Py_InitializeFromConfig(&config);
    if (PyStatus_Exception(status)) {
        goto exception;
    }
    PyConfig_Clear(&config);

    /* Optionally import the module; alternatively,
       import can be deferred until the embedded script
       imports it. */
    PyObject *pmodule = PyImport_ImportModule("spam");
    if (!pmodule) {
        PyErr_Print();
        fprintf(stderr, "Error: could not import module 'spam'\n");
    }

    // ... use Python C API here ...

    return 0;

  exception:
     PyConfig_Clear(&config);
     Py_ExitStatusException(status);
}

Anteckning

Om du deklarerar en global variabel eller en lokal statisk variabel kan modulen få oavsiktliga bieffekter vid ominitialisering, till exempel när du tar bort poster från sys.modules eller importerar kompilerade moduler till flera tolkar inom en process (eller efter en fork() utan en mellanliggande exec()). Om modultillståndet ännu inte är helt isolerat, bör författare överväga att markera modulen som att den inte har stöd för undertolkare (via Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED).

En mer omfattande exempelmodul ingår i Python-källdistributionen som Modules/xxlimited.c. Denna fil kan användas som en mall eller helt enkelt läsas som ett exempel.

1.5. Sammanställning och länkning

Det finns ytterligare två saker att göra innan du kan använda ditt nya tillägg: att kompilera och länka det med Python-systemet. Om du använder dynamisk laddning kan detaljerna bero på vilken typ av dynamisk laddning ditt system använder; se kapitlen om att bygga tilläggsmoduler (kapitel Bygga C- och C++-tillägg) och ytterligare information som endast gäller för att bygga på Windows (kapitel Bygga C- och C++-tillägg i Windows) för mer information om detta.

Om du inte kan använda dynamisk laddning, eller om du vill göra din modul till en permanent del av Python-tolken, måste du ändra konfigurationsinställningarna och bygga om tolken. Lyckligtvis är detta mycket enkelt på Unix: placera bara din fil (spammodule.c till exempel) i katalogen Modules/ i en uppackad källkodsdistribution, lägg till en rad i filen Modules/Setup.local som beskriver din fil:

skräppost spammodule.o

och bygga om tolken genom att köra make i toplevel-katalogen. Du kan också köra make i underkatalogen Modules/, men då måste du först bygga om Makefile där genom att köra ’make Makefile’. (Detta är nödvändigt varje gång du ändrar filen Setup)

Om din modul kräver ytterligare bibliotek att länka med kan dessa också anges på raden i konfigurationsfilen, till exempel:

spam spammodule.o -lX11

1.6. Anropa Python-funktioner från C

Hittills har vi koncentrerat oss på att göra C-funktioner anropsbara från Python. Det omvända är också användbart: att anropa Python-funktioner från C. Detta är särskilt fallet för bibliotek som stöder så kallade ”callback”-funktioner. Om ett C-gränssnitt använder sig av callbacks behöver motsvarande Python ofta tillhandahålla en callback-mekanism till Python-programmeraren; implementeringen kräver att Pythons callback-funktioner anropas från en C-callback. Andra användningsområden är också tänkbara.

Lyckligtvis är det lätt att anropa Python-tolken rekursivt och det finns ett standardgränssnitt för att anropa en Python-funktion. (Jag ska inte uppehålla mig vid hur man anropar Python-parsern med en viss sträng som indata — om du är intresserad kan du titta på implementeringen av kommandoradsalternativet -c i Modules/main.c från Pythons källkod)

Att anropa en Python-funktion är enkelt. Först måste Python-programmet på något sätt skicka Python-funktionsobjektet till dig. Du bör tillhandahålla en funktion (eller något annat gränssnitt) för att göra detta. När denna funktion anropas sparar du en pekare till Python-funktionsobjektet (var noga med att Py_INCREF() det!) i en global variabel — eller var du vill. Till exempel kan följande funktion vara en del av en moduldefinition:

static PyObject *my_callback = NULL;

static PyObject *
my_set_callback(PyObject *dummy, PyObject *args)
{
    PyObject *result = NULL;
    PyObject *temp;

    if (PyArg_ParseTuple(args, "O:set_callback", &temp)) {
        if (!PyCallable_Check(temp)) {
            PyErr_SetString(PyExc_TypeError, "parameter must be callable");
            return NULL;
        }
        Py_XINCREF(temp);         /* Add a reference to new callback */
        Py_XDECREF(my_callback);  /* Dispose of previous callback */
        my_callback = temp;       /* Remember new callback */
        /* Boilerplate to return "None" */
        Py_INCREF(Py_None);
        result = Py_None;
    }
    return result;
}

Denna funktion måste registreras hos tolken med hjälp av flaggan METH_VARARGS; detta beskrivs i avsnitt Modulens metodtabell och initialiseringsfunktion. Funktionen PyArg_ParseTuple() och dess argument finns dokumenterade i avsnitt Extrahera parametrar i tilläggsfunktioner.

Makrot Py_XINCREF() och Py_XDECREF() ökar/de minskar referensantalet för ett objekt och är säkra i närvaro av NULL-pekare (men observera att temp inte kommer att vara NULL i detta sammanhang). Mer information om dem finns i avsnittet Referensräkningar.

Senare, när det är dags att anropa funktionen, anropar du C-funktionen PyObject_CallObject(). Denna funktion har två argument, båda pekare till godtyckliga Python-objekt: Python-funktionen och argumentlistan. Argumentlistan måste alltid vara ett tuple-objekt, vars längd är antalet argument. För att anropa Python-funktionen utan argument, skicka in NULL, eller en tom tupel; för att anropa den med ett argument, skicka en singleton-tupel. Py_BuildValue() returnerar en tupel när dess formatsträng består av noll eller flera formatkoder mellan parenteser. Till exempel:

int arg;
PyObject *arglist;
PyObject *result;
...
arg = 123;
...
/* Time to call the callback */
arglist = Py_BuildValue("(i)", arg);
result = PyObject_CallObject(my_callback, arglist);
Py_DECREF(arglist);

PyObject_CallObject() returnerar en Python-objektpekare: detta är Python-funktionens returvärde. PyObject_CallObject() är ”referensräkningsneutral” med avseende på sina argument. I exemplet skapades en ny tupel för att fungera som argumentlista, som Py_DECREF() -ed omedelbart efter anropet av PyObject_CallObject().

Returvärdet för PyObject_CallObject() är ”nytt”: antingen är det ett helt nytt objekt, eller så är det ett befintligt objekt vars referensantal har ökats. Så om du inte vill spara det i en global variabel bör du på något sätt Py_DECREF() resultatet, även (särskilt!) om du inte är intresserad av dess värde.

Innan du gör detta är det dock viktigt att kontrollera att returvärdet inte är NULL. Om det är det, avslutas Python-funktionen med ett undantag. Om C-koden som anropade PyObject_CallObject() anropas från Python, bör den nu returnera en felindikation till sin Python-anropare, så att tolken kan skriva ut en stack trace, eller så att den anropande Python-koden kan hantera undantaget. Om detta inte är möjligt eller önskvärt, bör undantaget rensas genom att anropa PyErr_Clear(). Till exempel:

if (resultat == NULL)
    return NULL; /* Skicka felet tillbaka */
...använd resultatet...
Py_DECREF(resultat);

Beroende på det önskade gränssnittet till Pythons återuppringningsfunktion kan du också behöva tillhandahålla en argumentlista till PyObject_CallObject(). I vissa fall tillhandahålls argumentlistan också av Python-programmet, genom samma gränssnitt som specificerade callback-funktionen. Den kan då sparas och användas på samma sätt som funktionsobjektet. I andra fall kan du behöva konstruera en ny tupel att skicka som argumentlista. Det enklaste sättet att göra detta är att anropa Py_BuildValue(). Om du t.ex. vill skicka en integrerad händelsekod kan du använda följande kod:

PyObject *arglist;
...
arglist = Py_BuildValue("(l)", eventcode);
result = PyObject_CallObject(my_callback, arglist);
Py_DECREF(arglist);
if (result == NULL)
    return NULL; /* Pass error back */
/* Here maybe use the result */
Py_DECREF(result);

Notera placeringen av Py_DECREF(arglist) omedelbart efter anropet, före felkontrollen! Observera också att denna kod inte är komplett i strikt mening: Py_BuildValue() kan få slut på minne, och detta bör kontrolleras.

Du kan också anropa en funktion med nyckelordsargument genom att använda PyObject_Call(), som stöder argument och nyckelordsargument. Som i exemplet ovan använder vi Py_BuildValue() för att konstruera ordlistan.

PyObject *dict;
...
dict = Py_BuildValue("{s:i}", "name", val);
result = PyObject_Call(my_callback, NULL, dict);
Py_DECREF(dict);
if (result == NULL)
    return NULL; /* Pass error back */
/* Here maybe use the result */
Py_DECREF(result);

1.7. Extrahera parametrar i tilläggsfunktioner

Funktionen PyArg_ParseTuple() deklareras enligt följande:

int PyArg_ParseTuple(PyObject *arg, const char *format, ...);

Argumentet arg måste vara ett tuple-objekt som innehåller en argumentlista som skickas från Python till en C-funktion. Argumentet format måste vara en formatsträng, vars syntax förklaras i Tolkning av argument och skapande av värden i Python/C API Reference Manual. De återstående argumenten måste vara adresser till variabler vars typ bestäms av formatsträngen.

Observera att medan PyArg_ParseTuple() kontrollerar att Python-argumenten har de nödvändiga typerna, kan den inte kontrollera giltigheten av adresserna för C-variabler som skickas till anropet: om du gör misstag där kommer din kod förmodligen att krascha eller åtminstone skriva över slumpmässiga bitar i minnet. Så var försiktig!

Observera att alla Python-objektreferenser som tillhandahålls till den som anropar är lånade referenser; minska inte deras referensantal!

Några exempel på samtal:

#definiera PY_SSIZE_T_CLEAN
#inkludera <Python.h>
int ok;
int i, j;
lång k, l;
konst char *s;
Py_ssize_t storlek;

ok = PyArg_ParseTuple(args, ""); /* Inga argument */
    /* Python-anrop: f() */
ok = PyArg_ParseTuple(args, "s", &s); /* En sträng */
    /* Möjligt Python-anrop: f('whoops!') */
ok = PyArg_ParseTuple(args, "lls", &k, &l, &s); /* Två longs och en sträng */
    /* Möjligt Python-anrop: f(1, 2, 'tre') */
ok = PyArg_ParseTuple(args, "(ii)s#", &i, &j, &s, &size);
    /* Ett par ints och en sträng, vars storlek också returneras */
    /* Möjligt Python-anrop: f((1, 2), 'tre') */
{
    const char *file;
    const char *mode = "r";
    int bufsize = 0;
    ok = PyArg_ParseTuple(args, "s|si", &file, &mode, &bufsize);
    /* En sträng, och eventuellt en annan sträng och ett heltal */
    /* Möjliga Python-anrop:
       f('spam')
       f('spam', 'w')
       f('spam', 'wb', 100000) */
}
{
    int vänster, topp, höger, botten, h, v;
    ok = PyArg_ParseTuple(args, "((ii)(ii))(ii)",
             &left, &top, &right, &bottom, &h, &v);
    /* En rektangel och en punkt */
    /* Möjligt Python-anrop:
       f(((0, 0), (400, 300)), (10, 10)) */
}
{
    Py_komplex c;
    ok = PyArg_ParseTuple(args, "D:myfunction", &c);
    /* ett komplex, som också tillhandahåller ett funktionsnamn för fel */
    /* Möjligt Python-anrop: myfunction(1+2j) */
}

1.8. Nyckelordsparametrar för tilläggsfunktioner

Funktionen PyArg_ParseTupleAndKeywords() deklareras enligt följande:

int PyArg_ParseTupleAndKeywords(PyObject *arg, PyObject *kwdict,
                                const char *format, char * const *kwlist, ...);

Parametrarna arg och format är identiska med dem i funktionen PyArg_ParseTuple(). Parametern kwdict är den ordbok med nyckelord som tas emot som tredje parameter från Pythons runtime. Parametern kwlist är en NULL-avslutad lista med strängar som identifierar parametrarna; namnen matchas med typinformationen från format från vänster till höger. Vid framgång returnerar PyArg_ParseTupleAndKeywords() true, annars returnerar den false och ger upphov till ett lämpligt undantag.

Anteckning

Nästlade tupler kan inte analyseras när nyckelordsargument används! Nyckelordsparametrar som skickas in och som inte finns i kwlist kommer att orsaka TypeError.

Här är ett exempel på en modul som använder nyckelord, baserat på ett exempel av Geoff Philbrick (philbrick@hks.com):

#define PY_SSIZE_T_CLEAN
#include <Python.h>

static PyObject *
keywdarg_parrot(PyObject *self, PyObject *args, PyObject *keywds)
{
    int voltage;
    const char *state = "a stiff";
    const char *action = "voom";
    const char *type = "Norwegian Blue";

    static char *kwlist[] = {"voltage", "state", "action", "type", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|sss", kwlist,
                                     &voltage, &state, &action, &type))
        return NULL;

    printf("-- This parrot wouldn't %s if you put %i Volts through it.\n",
           action, voltage);
    printf("-- Lovely plumage, the %s -- It's %s!\n", type, state);

    Py_RETURN_NONE;
}

static PyMethodDef keywdarg_methods[] = {
    /* The cast of the function is necessary since PyCFunction values
     * only take two PyObject* parameters, and keywdarg_parrot() takes
     * three.
     */
    {"parrot", (PyCFunction)(void(*)(void))keywdarg_parrot, METH_VARARGS | METH_KEYWORDS,
     "Print a lovely skit to standard output."},
    {NULL, NULL, 0, NULL}   /* sentinel */
};

static struct PyModuleDef keywdarg_module = {
    .m_base = PyModuleDef_HEAD_INIT,
    .m_name = "keywdarg",
    .m_size = 0,
    .m_methods = keywdarg_methods,
};

PyMODINIT_FUNC
PyInit_keywdarg(void)
{
    return PyModuleDef_Init(&keywdarg_module);
}

1.9. Att bygga godtyckliga värden

Denna funktion är motsvarigheten till PyArg_ParseTuple(). Den deklareras på följande sätt:

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

Den känner igen en uppsättning formatenheter som liknar dem som känns igen av PyArg_ParseTuple(), men argumenten (som är indata till funktionen, inte utdata) får inte vara pekare, bara värden. Den returnerar ett nytt Python-objekt, lämpligt för att returnera från en C-funktion som anropas från Python.

En skillnad med PyArg_ParseTuple(): medan den senare kräver att dess första argument är en tupel (eftersom Python-argumentlistor alltid representeras som tuplar internt), bygger Py_BuildValue() inte alltid en tupel. Den bygger en tupel endast om dess formatsträng innehåller två eller fler formatenheter. Om formatsträngen är tom returnerar den None; om den innehåller exakt en formatenhet returnerar den det objekt som beskrivs av den formatenheten. Om du vill tvinga den att returnera en tupel av storlek 0 eller ett, sätter du formatsträngen i parentes.

Exempel (till vänster anropet, till höger det resulterande Python-värdet):

Py_BuildValue("")                        None
Py_BuildValue("i", 123)                  123
Py_BuildValue("iii", 123, 456, 789)      (123, 456, 789)
Py_BuildValue("s", "hello")              'hello'
Py_BuildValue("y", "hello")              b'hello'
Py_BuildValue("ss", "hello", "world")    ('hello', 'world')
Py_BuildValue("s#", "hello", 4)          'hell'
Py_BuildValue("y#", "hello", 4)          b'hell'
Py_BuildValue("()")                      ()
Py_BuildValue("(i)", 123)                (123,)
Py_BuildValue("(ii)", 123, 456)          (123, 456)
Py_BuildValue("(i,i)", 123, 456)         (123, 456)
Py_BuildValue("[i,i]", 123, 456)         [123, 456]
Py_BuildValue("{s:i,s:i}",
              "abc", 123, "def", 456)    {'abc': 123, 'def': 456}
Py_BuildValue("((ii)(ii)) (ii)",
              1, 2, 3, 4, 5, 6)          (((1, 2), (3, 4)), (5, 6))

1.10. Referensräkningar

I språk som C eller C++ är programmeraren ansvarig för dynamisk allokering och avallokering av minne på heapen. I C görs detta med hjälp av funktionerna malloc() och free(). I C++ används operatorerna new och delete med i stort sett samma innebörd och vi kommer att begränsa följande diskussion till C-fallet.

Varje minnesblock som allokerats med malloc() bör så småningom återföras till poolen av tillgängligt minne genom exakt ett anrop till free(). Det är viktigt att anropa free() vid rätt tidpunkt. Om adressen till ett block glöms bort men free() inte anropas för det, kan det minne som det upptar inte återanvändas förrän programmet avslutas. Detta kallas för en minnesläcka. Å andra sidan, om ett program anropar free() för ett block och sedan fortsätter att använda blocket, skapar det en konflikt med återanvändning av blocket genom ett annat malloc()-anrop. Detta kallas using freed memory. Det har samma dåliga konsekvenser som att referera till oinitialiserade data — kärndumpar, felaktiga resultat, mystiska krascher.

Vanliga orsaker till minnesläckage är ovanliga vägar genom koden. En funktion kan t.ex. allokera ett minnesblock, göra en beräkning och sedan frigöra blocket igen. Nu kan en ändring i kraven för funktionen lägga till ett test i beräkningen som upptäcker ett feltillstånd och kan återvända i förtid från funktionen. Det är lätt att glömma att frigöra det allokerade minnesblocket när man gör denna för tidiga exit, särskilt när det läggs till senare i koden. När sådana läckor väl har uppstått går de ofta oupptäckta under lång tid: felreturen sker bara i en liten del av alla anrop, och de flesta moderna maskiner har gott om virtuellt minne, så läckan blir bara uppenbar i en långvarig process som använder den läckande funktionen ofta. Därför är det viktigt att förhindra att läckor uppstår genom att ha en kodningskonvention eller strategi som minimerar den här typen av fel.

Eftersom Python använder sig mycket av malloc() och free(), behöver det en strategi för att undvika minnesläckor och användning av frigjort minne. Den valda metoden kallas referensräkning. Principen är enkel: varje objekt innehåller en räknare, som ökas när en referens till objektet lagras någonstans, och som minskas när en referens till det tas bort. När räknaren når noll har den sista referensen till objektet raderats och objektet är frigjort.

En alternativ strategi kallas automatic garbage collection. (Ibland kallas referensräkning också för en skräpinsamlingsstrategi, därav min användning av ”automatisk” för att skilja de två åt) Den stora fördelen med automatisk garbage collection är att användaren inte behöver anropa free() explicit. (En annan påstådd fördel är en förbättring av hastighet eller minnesanvändning — detta är dock inget hårt faktum.) Nackdelen är att det för C inte finns någon verkligt portabel automatisk garbage collector, medan referensräkning kan implementeras portabelt (så länge funktionerna malloc() och free() är tillgängliga — vilket C-standarden garanterar). Kanske kommer en dag en tillräckligt portabel automatisk skräpsamlare att finnas tillgänglig för C. Till dess får vi leva med referensräkning.

Python använder den traditionella referensräkningsimplementeringen, men erbjuder också en cykeldetektor som upptäcker referenscykler. Detta gör att applikationer inte behöver oroa sig för att skapa direkta eller indirekta cirkulära referenser; dessa är svagheten hos skräpsamling som implementeras med endast referensräkning. Referenscykler består av objekt som innehåller (eventuellt indirekta) referenser till sig själva, så att varje objekt i cykeln har ett referensantal som inte är noll. Typiska implementationer av referensräkning kan inte återta det minne som tillhör något objekt i en referenscykel, eller som refereras från objekten i cykeln, även om det inte finns några ytterligare referenser till själva cykeln.

Cykeldetektorn kan upptäcka skräpcykler och kan återta dem. Modulen gc exponerar ett sätt att köra detektorn (funktionen collect()), samt konfigurationsgränssnitt och möjligheten att inaktivera detektorn vid körning.

1.10.1. Referensräkning i Python

Det finns två makron, Py_INCREF(x) och Py_DECREF(x), som hanterar inkrementering och dekrementering av referensantalet. Py_DECREF() frigör också objektet när antalet når noll. För flexibilitetens skull anropar den inte free() direkt — utan den gör ett anrop via en funktionspekare i objektets type object. För detta ändamål (och andra) innehåller varje objekt också en pekare till sitt typobjekt.

Nu återstår den stora frågan: när ska man använda Py_INCREF(x) och Py_DECREF(x)? Låt oss först introducera några termer. Ingen ”äger” ett objekt, men du kan äga en referens till ett objekt. Ett objekts referensantal definieras nu som antalet ägda referenser till det. Ägaren till en referens är ansvarig för att anropa Py_DECREF() när referensen inte längre behövs. Äganderätten till en referens kan överföras. Det finns tre sätt att göra sig av med en ägd referens: skicka den vidare, lagra den eller anropa Py_DECREF(). Om man glömmer att göra sig av med en ägd referens uppstår en minnesläcka.

Det är också möjligt att låna [2] en referens till ett objekt. Låntagaren av en referens bör inte anropa Py_DECREF(). Låntagaren får inte behålla objektet längre än ägaren från vilken det lånades. Att använda en lånad referens efter att ägaren har gjort sig av med den riskerar att använda frigjort minne och bör undvikas helt [3].

Fördelen med att låna en referens jämfört med att äga den är att du inte behöver ta hand om referensen på alla möjliga vägar genom koden — med andra ord, med en lånad referens löper du inte risken att läcka när en för tidig exit tas. Nackdelen med att låna i stället för att äga är att det finns vissa subtila situationer där en lånad referens i till synes korrekt kod kan användas efter att ägaren som den lånades från i själva verket har gjort sig av med den.

En lånad referens kan ändras till en ägd referens genom att anropa Py_INCREF(). Detta påverkar inte statusen för den ägare från vilken referensen lånades — det skapar en ny ägd referens och ger ägaren fullt ansvar (den nya ägaren måste göra sig av med referensen på rätt sätt, liksom den tidigare ägaren).

1.10.2. Regler för ägande

När en objektreferens skickas in i eller ut ur en funktion är det en del av funktionens gränssnittsspecifikation om äganderätten överförs med referensen eller inte.

De flesta funktioner som returnerar en referens till ett objekt skickar äganderätten vidare med referensen. I synnerhet alla funktioner vars funktion är att skapa ett nytt objekt, till exempel PyLong_FromLong() och Py_BuildValue(), överför äganderätten till mottagaren. Även om objektet egentligen inte är nytt, får du ändå äganderätten till en ny referens till objektet. Till exempel upprätthåller PyLong_FromLong() en cache av populära värden och kan returnera en referens till ett cachat objekt.

Många funktioner som extraherar objekt från andra objekt överför också äganderätten med referensen, till exempel PyObject_GetAttrString(). Här är bilden dock inte lika tydlig eftersom några vanliga rutiner utgör undantag: PyTuple_GetItem(), PyList_GetItem(), PyDict_GetItem() och PyDict_GetItemString() returnerar alla referenser som du lånar från tupeln, listan eller ordboken.

Funktionen PyImport_AddModule() returnerar också en lånad referens, även om den faktiskt kan skapa det objekt den returnerar: detta är möjligt eftersom en ägd referens till objektet lagras i sys.modules.

När du skickar en objektreferens till en annan funktion lånar funktionen i allmänhet referensen från dig — om den behöver lagra den kommer den att använda Py_INCREF() för att bli en oberoende ägare. Det finns exakt två viktiga undantag från denna regel: PyTuple_SetItem() och PyList_SetItem(). Dessa funktioner tar över ägandet av det objekt som skickas till dem — även om de misslyckas! (Observera att PyDict_SetItem() och vänner inte tar över ägandet — de är ”normala.”)

När en C-funktion anropas från Python lånar den referenser till sina argument från den som anropar. Den som anropar äger en referens till objektet, så den lånade referensens livstid är garanterad tills funktionen returneras. Endast när en sådan lånad referens måste lagras eller skickas vidare, måste den omvandlas till en ägd referens genom att anropa Py_INCREF().

Den objektreferens som returneras från en C-funktion som anropas från Python måste vara en ägd referens — ägandet överförs från funktionen till den som anropar.

1.10.3. Tunn is

Det finns några situationer där en till synes harmlös användning av en lånad referens kan leda till problem. Dessa har alla att göra med implicita anrop av tolken, vilket kan leda till att ägaren av en referens gör sig av med den.

Det första och viktigaste fallet att känna till är att använda Py_DECREF() på ett orelaterat objekt medan man lånar en referens till ett listobjekt. Till exempel:

void
bug(PyObject *lista)
{
    PyObject *item = PyList_GetItem(list, 0);

    PyList_SetItem(lista, 1, PyLong_FromLong(0L));
    PyObject_Print(item, stdout, 0); /* BUG! */
}

Den här funktionen lånar först en referens till list[0], ersätter sedan list[1] med värdet 0 och skriver slutligen ut den lånade referensen. Ser ofarligt ut, eller hur? Men det är det inte!

Låt oss följa kontrollflödet till PyList_SetItem(). Listan äger referenser till alla sina objekt, så när objekt 1 ersätts måste den kasta det ursprungliga objektet 1. Låt oss nu anta att det ursprungliga objektet 1 var en instans av en användardefinierad klass, och låt oss vidare anta att klassen definierade en __del__()-metod. Om denna klassinstans har en referensräkning på 1 kommer avyttringen av den att anropa dess __del__()-metod. Internt anropar PyList_SetItem() Py_DECREF() på det ersatta objektet, vilket anropar det ersatta objektets motsvarande tp_dealloc-funktion. Under avallokeringen anropar tp_dealloc tp_finalize, som är mappad till metoden __del__() för klassinstanser (se PEP 442). Hela denna sekvens sker synkront inom anropet PyList_SetItem().

Eftersom den är skriven i Python kan metoden __del__() exekvera godtycklig Python-kod. Kan den kanske göra något för att ogiltigförklara referensen till item i bug()? Det kan du ge dig på! Förutsatt att listan som skickas till bug() är tillgänglig för metoden __del__(), skulle den kunna utföra ett uttalande med effekten del list[0], och förutsatt att detta var den sista referensen till det objektet, skulle den frigöra minnet som är associerat med det, och därmed ogiltigförklara item.

Lösningen, när du väl känner till källan till problemet, är enkel: öka referensantalet tillfälligt. Den korrekta versionen av funktionen lyder:

ogiltigt
no_bug(PyObject *lista)
{
    PyObject *item = PyList_GetItem(list, 0);

    Py_INCREF(item);
    PyList_SetItem(lista, 1, PyLong_FromLong(0L));
    PyObject_Print(objekt, stdout, 0);
    Py_DECREF(objekt);
}

Det här är en sann historia. En äldre version av Python innehöll varianter av denna bugg och någon tillbringade en avsevärd tid i en C-debugger för att räkna ut varför hans __del__()-metoder misslyckades…

Det andra fallet av problem med en lånad referens är en variant som involverar trådar. Normalt kan flera trådar i Python-tolken inte komma i vägen för varandra, eftersom det finns ett globalt lås som skyddar hela Pythons objektutrymme. Det är dock möjligt att tillfälligt frigöra detta lås med hjälp av makrot Py_BEGIN_ALLOW_THREADS, och att återta det med hjälp av Py_END_ALLOW_THREADS. Detta är vanligt vid blockerande I/O-anrop, för att låta andra trådar använda processorn medan de väntar på att I/O ska slutföras. Uppenbarligen har följande funktion samma problem som den föregående:

void
bug(PyObject *lista)
{
    PyObject *item = PyList_GetItem(list, 0);
    Py_BEGIN_ALLOW_THREADS
    ...något blockerande I/O-anrop...
    Py_END_ALLOW_THREADS
    PyObject_Print(item, stdout, 0); /* BUG! */
}

1.10.4. NULL-pekare

I allmänhet förväntar sig funktioner som tar objektreferenser som argument inte att du skickar dem NULL -pekare, och kommer att dumpa kärnan (eller orsaka senare kärndumpar) om du gör det. Funktioner som returnerar objektreferenser returnerar vanligtvis NULL endast för att indikera att ett undantag har inträffat. Anledningen till att man inte testar för NULL -argument är att funktioner ofta vidarebefordrar de objekt de tar emot till andra funktioner — om varje funktion skulle testa för NULL skulle det bli många överflödiga tester och koden skulle köras långsammare.

Det är bättre att testa för NULL endast vid ”källan:” när en pekare som kan vara NULL tas emot, till exempel från malloc() eller från en funktion som kan ge upphov till ett undantag.

Makron Py_INCREF() och Py_DECREF() kontrollerar inte för NULL pekare — men det gör däremot deras varianter Py_XINCREF() och Py_XDECREF().

Makron för att kontrollera en viss objekttyp (Pytype_Check()) kontrollerar inte för NULL pekare — återigen, det finns mycket kod som anropar flera av dessa i rad för att testa ett objekt mot olika olika förväntade typer, och detta skulle generera överflödiga tester. Det finns inga varianter med NULL kontroll.

C-funktionens anropsmekanism garanterar att den argumentlista som skickas till C-funktioner (args i exemplen) aldrig är NULL — i själva verket garanterar den att den alltid är en tupel [4].

Det är ett allvarligt fel att någonsin låta en NULL-pekare ”fly” till Python-användaren.

1.11. Skriva tillägg i C++

Det är möjligt att skriva tilläggsmoduler i C++. Vissa begränsningar gäller. Om huvudprogrammet (Python-tolken) kompileras och länkas av en C-kompilator kan globala eller statiska objekt med konstruktörer inte användas. Detta är inte ett problem om huvudprogrammet länkas av C++-kompilatorn. Funktioner som kommer att anropas av Python-tolken (i synnerhet modulinitialiseringsfunktioner) måste deklareras med hjälp av extern "C". Det är onödigt att bifoga Pythons headerfiler i extern "C" {...} — de använder denna form redan om symbolen __cplusplus är definierad (alla nyare C++-kompilatorer definierar denna symbol).

1.12. Tillhandahålla ett C API för en tilläggsmodul

Många tilläggsmoduler tillhandahåller bara nya funktioner och typer som kan användas från Python, men ibland kan koden i en tilläggsmodul vara användbar för andra tilläggsmoduler. Till exempel kan en tilläggsmodul implementera en typ ”collection” som fungerar som listor utan ordning. Precis som Pythons standardtyp list har ett C-API som tillåter tilläggsmoduler att skapa och manipulera listor, bör denna nya samlingstyp ha en uppsättning C-funktioner för direkt manipulation från andra tilläggsmoduler.

Vid första anblicken verkar detta enkelt: skriv bara funktionerna (naturligtvis utan att deklarera dem som ”statiska”), tillhandahåll en lämplig header-fil och dokumentera C API. Och det skulle faktiskt fungera om alla tilläggsmoduler alltid länkades statiskt med Python-tolken. När moduler används som delade bibliotek kan det dock hända att de symboler som definieras i en modul inte är synliga för en annan modul. Detaljerna kring synlighet beror på operativsystemet; vissa system använder ett globalt namnrymd för Python-tolken och alla tilläggsmoduler (Windows, till exempel), medan andra kräver en explicit lista över importerade symboler vid modullänkning (AIX är ett exempel), eller erbjuder ett urval av olika strategier (de flesta Unices). Och även om symbolerna är globalt synliga är det inte säkert att den modul vars funktioner man vill anropa har laddats in än!

Portabilitet kräver därför att man inte gör några antaganden om symbolers synlighet. Detta innebär att alla symboler i tilläggsmoduler bör deklareras static, med undantag för modulens initialiseringsfunktion, för att undvika namnkrockar med andra tilläggsmoduler (vilket diskuteras i avsnitt Modulens metodtabell och initialiseringsfunktion). Och det innebär att symboler som bör vara åtkomliga från andra tilläggsmoduler måste exporteras på ett annat sätt.

Python tillhandahåller en speciell mekanism för att skicka information på C-nivå (pekare) från en tilläggsmodul till en annan: Kapslar. En Capsule är en Python-datatyp som lagrar en pekare (void*). Kapslar kan bara skapas och nås via deras C API, men de kan skickas runt som vilket annat Python-objekt som helst. I synnerhet kan de tilldelas ett namn i en tilläggsmoduls namnrymd. Andra tilläggsmoduler kan sedan importera den här modulen, hämta värdet på det här namnet och sedan hämta pekaren från Capsule.

Det finns många sätt att använda kapslar för att exportera C API för en tilläggsmodul. Varje funktion kan få sin egen Capsule, eller så kan alla C API-pekare lagras i en array vars adress publiceras i en Capsule. Och de olika uppgifterna för att lagra och hämta pekarna kan fördelas på olika sätt mellan modulen som tillhandahåller koden och klientmodulerna.

Oavsett vilken metod du väljer är det viktigt att namnge dina kapslar på rätt sätt. Funktionen PyCapsule_New() tar emot en namnparameter (const char*); du får skicka in ett NULL namn, men vi uppmuntrar dig starkt att ange ett namn. Korrekt namngivna kapslar ger en viss grad av typsäkerhet under körning; det finns inget genomförbart sätt att skilja en namnlös kapsel från en annan.

I synnerhet bör kapslar som används för att exponera C API:er ges ett namn enligt följande konvention:

modulename.attributnamn

Bekvämlighetsfunktionen PyCapsule_Import() gör det enkelt att ladda ett C API som tillhandahålls via en Capsule, men bara om Capsulens namn matchar denna konvention. Detta beteende ger C API-användare en hög grad av säkerhet att den Capsule de laddar innehåller rätt C API.

Följande exempel visar ett tillvägagångssätt som lägger det mesta av bördan på författaren av den exporterande modulen, vilket är lämpligt för vanliga biblioteksmoduler. Den lagrar alla C API-pekare (bara en i exemplet!) i en array av void-pekare som blir värdet på en Capsule. Headerfilen som motsvarar modulen innehåller ett makro som tar hand om att importera modulen och hämta dess C API-pekare; klientmoduler behöver bara anropa detta makro innan de får tillgång till C API.

Den exporterande modulen är en modifiering av spam-modulen från avsnitt Ett enkelt exempel. Funktionen spam.system() anropar inte C-bibliotekets funktion system() direkt, utan en funktion PySpam_System(), som naturligtvis skulle göra något mer komplicerat i verkligheten (som att lägga till ”spam” till varje kommando). Denna funktion PySpam_System() exporteras också till andra tilläggsmoduler.

Funktionen PySpam_System() är en vanlig C-funktion, deklarerad static som allt annat:

static int
PySpam_System(const char *command)
{
    return system(command);
}

Funktionen spam_system() modifieras på ett trivialt sätt:

static PyObject *
spam_system(PyObject *self, PyObject *args)
{
    const char *command;
    int sts;

    if (!PyArg_ParseTuple(args, "s", &command))
        return NULL;
    sts = PySpam_System(command);
    return PyLong_FromLong(sts);
}

I början av modulen, direkt efter raden

#inkludera <Python.h>

ytterligare två rader måste läggas till:

#definiera SPAM_MODULE
#inkludera "spammodule.h"

#define används för att tala om för headerfilen att den ingår i den exporterande modulen, inte i en klientmodul. Slutligen måste modulens funktion mod_exec ta hand om initialiseringen av C API-pekaren array:

static int
spam_module_exec(PyObject *m)
{
    static void *PySpam_API[PySpam_API_pointers];
    PyObject *c_api_object;

    /* Initialize the C API pointer array */
    PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;

    /* Create a Capsule containing the API pointer array's address */
    c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL);

    if (PyModule_Add(m, "_C_API", c_api_object) < 0) {
        return -1;
    }

    return 0;
}

Observera att PySpam_API är deklarerat static; annars skulle pekararrayen försvinna när PyInit_spam() avslutas!

Huvuddelen av arbetet ligger i header-filen spammodule.h, som ser ut så här:

#ifndef Py_SPAMMODULE_H
#define Py_SPAMMODULE_H
#ifdef __cplusplus
extern "C" {
#endif

/* Header file for spammodule */

/* C API functions */
#define PySpam_System_NUM 0
#define PySpam_System_RETURN int
#define PySpam_System_PROTO (const char *command)

/* Total number of C API pointers */
#define PySpam_API_pointers 1


#ifdef SPAM_MODULE
/* This section is used when compiling spammodule.c */

static PySpam_System_RETURN PySpam_System PySpam_System_PROTO;

#else
/* This section is used in modules that use spammodule's API */

static void **PySpam_API;

#define PySpam_System \
 (*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])

/* Return -1 on error, 0 on success.
 * PyCapsule_Import will set an exception if there's an error.
 */
static int
import_spam(void)
{
    PySpam_API = (void **)PyCapsule_Import("spam._C_API", 0);
    return (PySpam_API != NULL) ? 0 : -1;
}

#endif

#ifdef __cplusplus
}
#endif

#endif /* !defined(Py_SPAMMODULE_H) */

Allt som en klientmodul behöver göra för att få tillgång till funktionen PySpam_System() är att anropa funktionen (eller snarare makrot) import_spam() i sin mod_exec-funktion:

static int
client_module_exec(PyObject *m)
{
    if (import_spam() < 0) {
        return -1;
    }
    /* additional initialization can happen here */
    return 0;
}

Den största nackdelen med detta tillvägagångssätt är att filen spammodule.h är ganska komplicerad. Grundstrukturen är dock densamma för varje funktion som exporteras, så den behöver bara läras in en gång.

Slutligen bör det nämnas att Capsules erbjuder ytterligare funktionalitet, som är särskilt användbar för minnesallokering och deallokering av pekaren som lagras i en Capsule. Detaljerna beskrivs i Python/C API Reference Manual i avsnittet Kapslar och i implementationen av Capsules (filerna Include/pycapsule.h och Objects/pycapsule.c i Pythons källkodsdistribution).

Fotnoter