Python Academy · Oppitunti

Pythonin C-laajennusmoduulin kirjoittaminen

Rakentakaa yksinkertainen .so-laajennus Python/C API:n avulla.

Oppitunti 4/413 vaihetta

Pythonin C-laajennusmoduulin kirjoittaminen on ilmainen Python Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Python Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Python Academy-kurssilla on yhteensä 4 oppituntia.

C-laajennuksen rakenne

Minimaalisessa C-laajennuksessa on metodifunktioita, metoditaulukko, moduulin määrittelyrakenne ja PyInit_-aloituspiste.

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

Argumenttien jäsentäminen

PyArg_ParseTuple(args, "ii", &a, &b) jäsentää Python-argumentit C-muuttujiksi. Muotoilukoodit ovat: i=int, d=double, s=char* ja 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);
}

Paluuarvojen muodostaminen

Muodostakaa Pythonin paluuarvot seuraavilla funktioilla: PyLong_FromLong, PyFloat_FromDouble, PyUnicode_FromString ja 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
}

Viitelaskenta

Jokaisella PyObject*-oliolla on viitemäärä. Käyttäkää Py_INCREF- ja Py_DECREF-makroja huolellisesti. C-funktioiden palauttamat paluuarvot antavat omistajuuden kutsujalle (varastetut viitteet).

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
}

Poikkeusten nostaminen

Käyttäkää PyErr_SetString(PyExc_ValueError, "msg")-kutsua Python-poikkeuksen nostamiseen C:stä ja palauttakaa sen jälkeen 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);
}

C-laajennusten setup.py

Käyttäkää setuptools.Extension-luokkaa C-lähdetiedostojen ilmoittamiseen. Kääntäkää komennolla 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)

Käännetyn laajennuksen käyttäminen

Kun laajennus on käännetty, tuokaa se käyttöön kuten mikä tahansa Python-moduuli. Python löytää sen etsimällä tiedostoa myext.so (tai Windowsissa tiedostoa .pyd).

# 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

Avainsana-argumentit

Käyttäkää PyArg_ParseTupleAndKeywords-funktiota yhdessä avainsanaluettelon kanssa, jotta C-funktiot tukevat avainsana-argumentteja.

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

Moduulitason vakiot

Lisätkää kokonaisluku- tai merkkijonovakioita moduuliin PyInit_-funktion avulla käyttämällä PyModule_AddIntConstant-funktiota.

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

GIL:n vapauttaminen

Ympäröikää puhdas C-työ komennoilla Py_BEGIN_ALLOW_THREADS ja Py_END_ALLOW_THREADS, jotta muut Python-säikeet voivat suorittaa koodia C-koodin aikana.

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

Laajennuksen testaaminen

Testatkaa C-laajennuksia niiden Python-rajapinnan kautta pytestillä. Erillisiä C-testityökaluja ei tarvita.

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

Pikatarkistus

Mitä C-laajennuksen funktion on palautettava osoittaakseen, että Python-poikkeus on asetettu?

Kertaus

C-laajennus tarvitsee metodifunktiot (argumenttien jäsentäminen ja PyObject*-arvon palauttaminen), metoditaulukon, moduulin määrittelyrakenteen ja PyInit_name()-funktion. Nostakaa poikkeuksia asettamalla ne PyErr_SetString-funktiolla ja palauttamalla NULL. Vapauttakaa GIL puhtaan C-työn ajaksi.

Aloita maksutta

Opi Python tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
76
Oppitunnit
320

Usein kysytyt kysymykset

Onko oppitunti ”Pythonin C-laajennusmoduulin kirjoittaminen” ilmainen?

Kyllä – oppitunnin ”Pythonin C-laajennusmoduulin kirjoittaminen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Python Academy-kurssin, päivitä CoddyKit PROhon. Python Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Pythonin C-laajennusmoduulin kirjoittaminen”?

Rakentakaa yksinkertainen .so-laajennus Python/C API:n avulla. Harjoittelet Python Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Python Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Python Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Pythonin C-laajennusmoduulin kirjoittaminen”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Python Academy-oppitunnilla?

Kyllä. Jokainen Python Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Miksi C-laajennuksia käytetään? Käyttötapaukset ja kompromissit
  2. ctypes: C-kirjastojen kutsuminen Pythonista
  3. cffi: C:n vierasfunktiorajapinta
  4. Pythonin C-laajennusmoduulin kirjoittaminen
← Takaisin: Python Academy