Python Academy · Lektion

Skrivning af et Python-C-udvidelsesmodul

Opret en enkel .so-udvidelse med Python/C-API'et.

Lektion 4 af 413 trin

Skrivning af et Python-C-udvidelsesmodul er en gratis Python Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Python Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Python Academy-kurset indeholder 4 lektioner i alt.

Opbygningen af en C-udvidelse

En minimal C-udvidelse har: metodefunktioner, en metodetabel, en moduldefinitionsstruktur og et PyInit_-indgangspunkt.

// myext.c skeleton
#include <Python.h>

static PyObject* say_hello(PyObject* self, PyObject* args) {
    Py_RETURN_NONE;
}

static PyMethodDef methods[] = {
    {"say_hello", say_hello, METH_NOARGS, "Print hello"},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef module = {
    PyModuleDef_HEAD_INIT, "myext", NULL, -1, methods
};

PyMODINIT_FUNC PyInit_myext(void) {
    return PyModule_Create(&module);
}

Fortolkning af argumenter

PyArg_ParseTuple(args, "ii", &a, &b) fortolker Python-argumenter til C-variabler. Formatkoder: i=int, d=double, s=char*, O=PyObject*.

static PyObject* add(PyObject* self, PyObject* args) {
    int a, b;
    if (!PyArg_ParseTuple(args, "ii", &a, &b))
        return NULL;
    return PyLong_FromLong(a + b);
}

Returnering af værdier

Opret Python-returværdier med: PyLong_FromLong, PyFloat_FromDouble, PyUnicode_FromString, Py_BuildValue.

// Return a Python tuple (int, float)
static PyObject* stats(PyObject* self, PyObject* args) {
    int n = 10;
    double avg = 5.0;
    return Py_BuildValue("(id)", n, avg);
    // Py_BuildValue format: i=int d=double s=str
}

Referencetælling

Hvert PyObject* har en referencetæller. Brug Py_INCREF/Py_DECREF med omtanke. Returværdier fra C-funktioner giver den kaldende part ejerskab (stjålne referencer).

static PyObject* make_list(PyObject* self, PyObject* args) {
    PyObject* lst = PyList_New(3);
    for (int i = 0; i < 3; i++) {
        // PyList_SET_ITEM steals the reference:
        PyList_SET_ITEM(lst, i, PyLong_FromLong(i));
    }
    return lst;   // caller owns the list
}

Udløsning af undtagelser

Brug PyErr_SetString(PyExc_ValueError, "msg") til at udløse en Python-undtagelse fra C, og returnér derefter NULL.

static PyObject* safe_div(PyObject* self, PyObject* args) {
    int a, b;
    if (!PyArg_ParseTuple(args, "ii", &a, &b)) return NULL;
    if (b == 0) {
        PyErr_SetString(PyExc_ZeroDivisionError, "division by zero");
        return NULL;
    }
    return PyLong_FromLong(a / b);
}

setup.py til C-udvidelser

Brug setuptools.Extension til at deklarere C-kildefilerne. Byg med python setup.py build_ext --inplace.

# setup.py
from setuptools import setup, Extension

setup(
    name="myext",
    ext_modules=[
        Extension(
            "myext",
            sources=["myext.c"],
            extra_compile_args=["-O2"],
        )
    ]
)
# python setup.py build_ext --inplace
# import myext; myext.add(3, 4)

Brug af den byggede udvidelse

Når udvidelsen er bygget, skal du importere den som ethvert andet Python-modul. Python finder den ved at lede efter myext.so (eller .pyd på Windows).

# After: python setup.py build_ext --inplace
import myext
print(myext.add(3, 4))        # 7
print(myext.safe_div(10, 2))  # 5
# myext.safe_div(1, 0)         # ZeroDivisionError

Navngivne argumenter

Brug PyArg_ParseTupleAndKeywords sammen med en liste over nøgleord for at understøtte navngivne argumenter i C-funktioner.

static char* kwargs[] = {"x", "y", NULL};

static PyObject* hypot_c(PyObject* self,
                          PyObject* args,
                          PyObject* kw) {
    double x, y;
    if (!PyArg_ParseTupleAndKeywords(args, kw, "dd",
                                     kwargs, &x, &y))
        return NULL;
    return PyFloat_FromDouble(sqrt(x*x + y*y));
}

Konstanter på modulniveau

Tilføj heltals- eller strengkonstanter til modulet i PyInit_ ved hjælp af PyModule_AddIntConstant.

PyMODINIT_FUNC PyInit_myext(void) {
    PyObject* m = PyModule_Create(&module);
    if (!m) return NULL;
    PyModule_AddIntConstant(m, "VERSION", 1);
    PyModule_AddStringConstant(m, "AUTHOR", "Alice");
    return m;
}

Frigivelse af GIL

Pak rent C-arbejde ind i Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS for at lade andre Python-tråde køre, mens C-koden udføres.

static PyObject* heavy(PyObject* self, PyObject* args) {
    long n;
    if (!PyArg_ParseTuple(args, "l", &n)) return NULL;
    long result;
    Py_BEGIN_ALLOW_THREADS
        result = slow_c_computation(n);  // GIL released
    Py_END_ALLOW_THREADS
    return PyLong_FromLong(result);
}

Test af udvidelsen

Test C-udvidelser gennem deres Python-grænseflade med pytest. Der kræves ingen særlige C-testværktøjer.

# test_myext.py
import pytest
import myext

def test_add(): assert myext.add(3, 4) == 7
def test_zero_div():
    with pytest.raises(ZeroDivisionError):
        myext.safe_div(1, 0)

Hurtigt tjek

Hvad skal en funktion i en C-udvidelse returnere for at angive, at der er blevet sat en Python-undtagelse?

Opsummering

En C-udvidelse kræver: metodefunktioner (fortolkning af argumenter, returnering af PyObject*), en metodetabel, en moduldefinitionsstruktur og PyInit_name(). Udløs undtagelser ved at angive dem med PyErr_SetString og returnere NULL. Frigiv GIL ved rent C-arbejde.

Gratis at komme i gang

Lær Python med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
76
Lektioner
320

Ofte stillede spørgsmål

Er lektionen “Skrivning af et Python-C-udvidelsesmodul” gratis?

Ja — hele teksten til “Skrivning af et Python-C-udvidelsesmodul” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Python Academy-kurset, skal du opgradere til CoddyKit PRO. Python Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Skrivning af et Python-C-udvidelsesmodul”?

Opret en enkel .so-udvidelse med Python/C-API'et. Du øver dig i Python Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Python Academy?

Der kræves ingen tidligere erfaring. Python Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “Skrivning af et Python-C-udvidelsesmodul”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Python Academy-lektion?

Ja. Alle Python Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Hvorfor C-udvidelser? Anvendelser og afvejninger
  2. ctypes: Kald af C-biblioteker fra Python
  3. cffi: C Foreign Function Interface
  4. Skrivning af et Python-C-udvidelsesmodul
← Tilbage til Python Academy