Definiera tilläggsmoduler

En C-utökning för CPython är ett delat bibliotek (till exempel en .so -fil på Linux, .pyd DLL på Windows) som kan laddas in i Python-processen (till exempel kompileras den med kompatibla kompilatorinställningar) och som exporterar en initialiseringsfunktion.

För att kunna importeras som standard (dvs. av importlib.machinery.ExtensionFileLoader) måste det delade biblioteket finnas tillgängligt på sys.path och ha namn efter modulnamnet plus ett tillägg som anges i importlib.machinery.EXTENSION_SUFFIXES.

Anteckning

Att bygga, paketera och distribuera tilläggsmoduler görs bäst med verktyg från tredje part och omfattas inte av det här dokumentet. Ett lämpligt verktyg är Setuptools, vars dokumentation finns på https://setuptools.pypa.io/en/latest/setuptools.html.

Normalt returnerar initialiseringsfunktionen en moduldefinition som initierats med hjälp av PyModuleDef_Init(). Detta gör det möjligt att dela upp skapandeprocessen i flera faser:

  • Innan någon väsentlig kod exekveras kan Python avgöra vilka funktioner som modulen stöder, och den kan anpassa miljön eller vägra att ladda ett inkompatibelt tillägg.

  • Som standard skapar Python själv modulobjektet - det vill säga, det gör motsvarande object.__new__() för klasser. Den ställer också in initiala attribut som __package__ och __loader__.

  • Därefter initieras modulobjektet med hjälp av tilläggsspecifik kod – motsvarande __init__() för klasser.

Detta kallas multifasinitialisering för att skilja det från det äldre (men fortfarande stöds) enfasinitialiserings-schemat, där initialiseringsfunktionen returnerar en helt konstruerad modul. Se avsnittet om enfasinitialisering under för mer information.

Ändrad i version 3.5: Lagt till stöd för flerfasinitialisering (PEP 489).

Flera modulinstanser

Som standard är tilläggsmoduler inte singletons. Om till exempel sys.modules-posten tas bort och modulen importeras på nytt, skapas ett nytt modulobjekt som vanligtvis fylls på med nya metod- och typobjekt. Den gamla modulen är föremål för normal skräpinsamling. Detta speglar beteendet hos rena Python-moduler.

Ytterligare modulinstanser kan skapas i sub-interpreters eller efter ominitialisering av Python-körtiden (Py_Finalize() och Py_Initialize()). I dessa fall skulle delning av Python-objekt mellan modulinstanser sannolikt orsaka krascher eller odefinierat beteende.

För att undvika sådana problem bör varje instans av en tilläggsmodul vara isolerad: ändringar i en instans bör inte implicit påverka de andra, och allt tillstånd som ägs av modulen, inklusive referenser till Python-objekt, bör vara specifikt för en viss modulinstans. Se Isolering av tilläggsmoduler för mer information och en praktisk guide.

Ett enklare sätt att undvika dessa problem är raising an error on repeated initialization.

Alla moduler förväntas ha stöd för sub-interpreters, eller på annat sätt uttryckligen signalera att stöd saknas. Detta uppnås vanligtvis genom isolering eller blockering av upprepad initialisering, enligt ovan. En modul kan också begränsas till huvudtolken med hjälp av Py_mod_multiple_interpreters slot.

Initialiseringsfunktion

Den initialiseringsfunktion som definieras av en tilläggsmodul har följande signatur:

PyObject *PyInit_modulename(void)

Dess namn bör vara PyInit_<name>, med <name> ersatt av namnet på modulen.

För moduler med ASCII-namn måste funktionen istället heta PyInit_<name>, med <name> ersatt av modulens namn. Vid användning av Initialisering i flera faser är modulnamn som inte är ASCII tillåtna. I detta fall är namnet på initialiseringsfunktionen PyInitU_<name>, med <name> kodat med Pythons punycode-kodning med bindestreck ersatta av understreck. I Python:

def initfunc_name(namn):
    try:
        suffix = b'_' + name.encode('ascii')
    except UnicodeEncodeError:
        suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
    return b'PyInit' + suffix

Vi rekommenderar att du definierar initialiseringsfunktionen med hjälp av ett hjälpmakro:

PyMODINIT_FUNC

Deklarera en initialiseringsfunktion för en tilläggsmodul. Detta makro:

  • anger returtypen PyObject*,

  • lägger till eventuella speciella länkdeklarationer som krävs av plattformen, och

  • för C++, deklarerar funktionen som extern "C".

Till exempel skulle en modul som heter spam definieras på följande sätt:

static struct PyModuleDef spam_module = {
    .m_base = PyModuleDef_HEAD_INIT,
    .m_name = "spam",
    ...
};

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

Det är möjligt att exportera flera moduler från ett enda delat bibliotek genom att definiera flera initialiseringsfunktioner. För att importera dem måste man dock använda symboliska länkar eller en anpassad importör, eftersom endast den funktion som motsvarar filnamnet hittas som standard. Se avsnittet Flera moduler i ett bibliotek i PEP 489 för mer information.

Initialiseringsfunktionen är vanligtvis det enda icke-statiska objektet som definieras i modulens C-källa.

Initialisering i flera faser

Normalt returnerar initialiseringsfunktionen (PyInit_modulename) en PyModuleDef -instans med icke- NULL m_slots. Innan den returneras måste PyModuleDef -instansen initialiseras med hjälp av följande funktion:

PyObject *PyModuleDef_Init(PyModuleDef *def)
En del av Stabil ABI sedan version 3.5.

Säkerställ att en moduldefinition är ett korrekt initialiserat Python-objekt som korrekt rapporterar sin typ och ett referensantal.

Returnerar def som kastas till PyObject*, eller NULL om ett fel inträffade.

Anrop av denna funktion krävs för Initialisering i flera faser. Den bör inte användas i andra sammanhang.

Observera att Python förutsätter att PyModuleDef -strukturer är statiskt allokerade. Denna funktion kan returnera antingen en ny referens eller en lånad; denna referens får inte släppas.

Tillagd i version 3.5.

Legacy enfasig initialisering

Observera

Enfasinitialisering är en äldre mekanism för att initiera tilläggsmoduler, med kända nackdelar och designfel. Författarna till tilläggsmoduler uppmanas att använda flerfasinitialisering i stället.

Vid enfasig initialisering ska initialiseringsfunktionen (PyInit_modulename) skapa, fylla på och returnera ett modulobjekt. Detta görs vanligen med PyModule_Create() och funktioner som PyModule_AddObjectRef().

Enfasinitialisering skiljer sig från default på följande sätt:

  • Enfasmoduler är, eller snarare innehåller, ”singletons”.

    När modulen initieras för första gången sparar Python innehållet i modulens __dict__ (det vill säga, typiskt sett, modulens funktioner och typer).

    För efterföljande import anropar Python inte initialiseringsfunktionen igen. Istället skapas ett nytt modulobjekt med en ny __dict__ och det sparade innehållet kopieras till det. Till exempel, givet en enfasmodul _testsinglephase [1] som definierar en funktion sum och en undantagsklass error:

    >>> import sys
    >>> import _testsinglephase as one
    >>> del sys.modules['_testsinglephase']
    >>> import _testsinglephase as two
    >>> one is two
    False
    >>> one.__dict__ is two.__dict__
    False
    >>> one.sum is two.sum
    True
    >>> one.error is two.error
    True
    

    Det exakta beteendet bör betraktas som en detalj i CPython-implementeringen.

  • För att kringgå det faktum att PyInit_modulename inte tar ett spec-argument, sparas en del av importmaskineriet och tillämpas på den första lämpliga modulen som skapas under PyInit_modulename -anropet. Specifikt, när en undermodul importeras, preponderar denna mekanism det överordnade paketnamnet till modulens namn.

    En enfasig funktion av typen PyInit_modulename bör skapa ”sitt” modulobjekt så snart som möjligt, innan några andra modulobjekt kan skapas.

  • Modulnamn som inte är ASCII (PyInitU_modulename) stöds inte.

  • Enfasmoduler stöder funktioner för moduluppslagning som PyState_FindModule().