0Pricing
Python Academy · Lezione

Scrittura di un modulo di estensione C per Python

Costruisca una semplice estensione .so utilizzando l'API Python/C.

Scrittura di un modulo di estensione C per Python è una lezione Python Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Python Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Python Academy include 4 lezioni in totale.

Anatomia di un'estensione C

Un'estensione C minima comprende: funzioni dei metodi, una tabella dei metodi, una struct di definizione del modulo e un punto di ingresso PyInit_.

// 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);
}

Analisi degli argomenti

PyArg_ParseTuple(args, "ii", &a, &b) analizza gli argomenti Python e li inserisce in variabili C. Codici di formato: 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);
}

Restituzione dei valori

Costruisca i valori restituiti a Python con: 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
}

Conteggio dei riferimenti

Ogni PyObject* ha un conteggio dei riferimenti. Utilizzi Py_INCREF/Py_DECREF con cautela. I valori restituiti dalle funzioni C trasferiscono al chiamante la proprietà (riferimenti rubati).

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
}

Sollevare eccezioni

Utilizzi PyErr_SetString(PyExc_ValueError, "msg") per sollevare un'eccezione Python da C, quindi restituisca 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 per le estensioni C

Utilizzi setuptools.Extension per dichiarare i file sorgente C. Compili con 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)

Utilizzo dell'estensione compilata

Una volta compilata, importi l'estensione come qualsiasi modulo Python. Python la trova cercando myext.so o .pyd in 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

Argomenti con nome

Utilizzi PyArg_ParseTupleAndKeywords insieme a un elenco di keyword per supportare gli argomenti con nome nelle funzioni C.

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));
}

Costanti a livello di modulo

Aggiunga costanti intere o stringa al modulo in PyInit_ utilizzando 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;
}

Rilascio del GIL

Racchiuda il lavoro C puro tra Py_BEGIN_ALLOW_THREADS e Py_END_ALLOW_THREADS per consentire l'esecuzione degli altri thread Python mentre viene eseguito il codice C.

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 dell'estensione

Esegua i test delle estensioni C tramite la loro interfaccia Python usando pytest. Non sono necessari strumenti di test C specifici.

# 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)

Verifica rapida

Che cosa deve restituire una funzione di un'estensione C per segnalare che è stata impostata un'eccezione Python?

Riepilogo

Un'estensione C richiede: funzioni dei metodi (analizzano gli argomenti e restituiscono PyObject*), una tabella dei metodi, una struct di definizione del modulo e PyInit_name(). Sollevi le eccezioni impostandole con PyErr_SetString e restituendo NULL. Rilasci il GIL per il lavoro C puro.

Domande Frequenti

La lezione «Scrittura di un modulo di estensione C per Python» è gratuita?

Sì — il testo completo di «Scrittura di un modulo di estensione C per Python» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Python Academy, passa a CoddyKit PRO. Il corso Python Academy include 4 lezioni in totale.

Cosa imparerò in «Scrittura di un modulo di estensione C per Python»?

Costruisca una semplice estensione .so utilizzando l'API Python/C. Eserciti Python Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Python Academy?

Non è richiesta alcuna esperienza precedente. Python Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Scrittura di un modulo di estensione C per Python»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Python Academy?

Sì. Ogni lezione Python Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Perché le estensioni C? Casi d'uso e compromessi
  2. ctypes: chiamare librerie C da Python
  3. cffi: interfaccia per funzioni esterne C
  4. Scrittura di un modulo di estensione C per Python
← Torna a Python Academy