0Pricing
Python Academy · Lección

Escritura de un módulo de extensión C para Python

Cree una extensión .so sencilla mediante la API de Python/C.

Escritura de un módulo de extensión C para Python es una lección gratuita de Python Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Python Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Python Academy incluye 4 lecciones en total.

Anatomía de una extensión de C

Una extensión de C mínima tiene funciones de métodos, una tabla de métodos, una estructura de definición del módulo y un punto de entrada 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);
}

Análisis de argumentos

PyArg_ParseTuple(args, "ii", &a, &b) analiza los argumentos de Python y los convierte en variables de C. Códigos de 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);
}

Devolución de valores

Construya valores de retorno de 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
}

Conteo de referencias

Cada PyObject* tiene un contador de referencias. Use Py_INCREF/Py_DECREF con cuidado. Los valores de retorno de las funciones de C transfieren la propiedad al llamador (referencias robadas).

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
}

Lanzamiento de excepciones

Use PyErr_SetString(PyExc_ValueError, "msg") para lanzar una excepción de Python desde C y, a continuación, devuelva 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 para extensiones de C

Use setuptools.Extension para declarar los archivos de código fuente de C. Compile 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)

Uso de la extensión compilada

Una vez compilada, importe la extensión como cualquier módulo de Python. Python la encuentra buscando myext.so (o .pyd en 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

Argumentos con nombre

Use PyArg_ParseTupleAndKeywords con una lista de palabras clave para admitir argumentos con nombre en las funciones de 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));
}

Constantes a nivel de módulo

Añada constantes enteras o de cadena al módulo en PyInit_ mediante 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;
}

Liberación del GIL

Rodee el trabajo realizado exclusivamente en C con Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS para permitir que se ejecuten otros hilos de Python mientras se ejecuta el código de 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);
}

Pruebas de la extensión

Pruebe las extensiones de C mediante su interfaz de Python con pytest. No se necesitan herramientas especiales de pruebas para C.

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

Comprobación rápida

¿Qué debe devolver una función de una extensión de C para indicar que se ha establecido una excepción de Python?

Recapitulación

Una extensión de C necesita funciones de métodos (analizar argumentos y devolver PyObject*), una tabla de métodos, una estructura de definición del módulo y PyInit_name(). Lance excepciones estableciéndolas con PyErr_SetString y devolviendo NULL. Libere el GIL para el trabajo realizado exclusivamente en C.

Preguntas frecuentes

¿La lección «Escritura de un módulo de extensión C para Python» es gratis?

Sí — el texto completo de «Escritura de un módulo de extensión C para Python» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Python Academy, actualiza a CoddyKit PRO. El curso de Python Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Escritura de un módulo de extensión C para Python»?

Cree una extensión .so sencilla mediante la API de Python/C. Practicas Python Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Python Academy?

No se requiere experiencia previa. Python Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Escritura de un módulo de extensión C para Python»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Python Academy?

Sí. Cada lección de Python Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. ¿Por qué extensiones C? Casos de uso y compensaciones
  2. ctypes: llamada a bibliotecas C desde Python
  3. cffi: interfaz de funciones externas de C
  4. Escritura de un módulo de extensión C para Python
← Volver a Python Academy