0Pricing
Python Academy · درس

كتابة وحدة امتداد C لـ Python

أنشئ امتداد .so بسيطاً باستخدام واجهة Python/C API

كتابة وحدة امتداد C لـ Python درس مجاني في Python Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Python Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Python Academy 4 دروس في المجموع.

بنية امتداد C

يتكوّن امتداد C الأدنى من: دوال الأساليب، وجدول أساليب، وبنية تعريف الوحدة، ونقطة إدخال 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);
}

تحليل المعاملات

تحلّل PyArg_ParseTuple(args, "ii", &a, &b) معاملات Python إلى متغيرات C. رموز التنسيق: 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);
}

إعادة القيم

أنشئ قيم الإرجاع في Python باستخدام: 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
}

عدّ المراجع

يمتلك كل PyObject* عددًا للمراجع. استخدم Py_INCREF/Py_DECREF بحذر. تمنح القيم المُعادة من دوال C المستدعيَ ملكيةَ القيمة، أي تكون المراجع منقولة الملكية.

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
}

إطلاق الاستثناءات

استخدم PyErr_SetString(PyExc_ValueError, "msg") لإطلاق استثناء Python من C، ثم أعد 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 لامتدادات C

استخدم setuptools.Extension للتصريح عن ملفات مصدر C. أنشئ الامتداد باستخدام 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)

استخدام الامتداد المُنشأ

بعد إنشائه، استورد الامتداد مثل أي وحدة Python. تعثر Python عليه بالبحث عن myext.so، أو .pyd في 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

المعاملات المسماة

استخدم PyArg_ParseTupleAndKeywords مع قائمة بالكلمات المفتاحية لدعم المعاملات المسماة في دوال 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));
}

الثوابت على مستوى الوحدة

أضف الثوابت الصحيحة أو النصية إلى الوحدة في PyInit_ باستخدام 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;
}

تحرير GIL

غلّف عمل C الخالص باستخدام Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS للسماح لخيوط Python الأخرى بالعمل أثناء تنفيذ كود 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);
}

اختبار الامتداد

اختبر امتدادات C عبر واجهة Python الخاصة بها باستخدام pytest. لا حاجة إلى أدوات اختبار خاصة بلغة 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)

تحقق سريع

ما الذي يجب أن تعيده دالة امتداد C للإشارة إلى أنه تم ضبط استثناء في Python؟

مراجعة

يحتاج امتداد C إلى: دوال أساليب تحلّل المعاملات وتعيد PyObject*، وجدول أساليب، وبنية تعريف الوحدة، وPyInit_name(). أطلق الاستثناءات بضبطها باستخدام PyErr_SetString وإعادة NULL. حرّر GIL عند تنفيذ عمل C خالص.

الأسئلة الشائعة

هل درس «كتابة وحدة امتداد C لـ Python» مجاني؟

نعم — نص درس «كتابة وحدة امتداد C لـ Python» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Python Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Python Academy 4 دروس في المجموع.

ماذا ستتعلم في «كتابة وحدة امتداد C لـ Python»؟

أنشئ امتداد .so بسيطاً باستخدام واجهة Python/C API تتمرن على Python Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Python Academy؟

لا تُشترط خبرة سابقة. Python Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «كتابة وحدة امتداد C لـ Python»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Python Academy هذا؟

نعم. كل درس في Python Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. لماذا امتدادات C؟ حالات الاستخدام والمفاضلات
  2. ctypes: استدعاء مكتبات C من Python
  3. cffi: واجهة الدوال الأجنبية لـ C
  4. كتابة وحدة امتداد C لـ Python
← العودة إلى Python Academy