إعـــــــلان

تقليص
لا يوجد إعلان حتى الآن.

Extending Python with C

تقليص
X
 
  • تصفية - فلترة
  • الوقت
  • عرض
إلغاء تحديد الكل
مشاركات جديدة

  • Extending Python with C

    Extending Python with C

    الموضوع خاضع للرخصة السفاحية
    وإهداء ل صوفى وستورم وجراى
    ماهى ال Extensions ؟
    هى امتدادات لل Python مكتوبة بال C او C-Like مثل ال C++ على سبيل المثال

    سهل كتابة extensions لل Python ولكن مالهدف ؟
    الهدف إنك تضيف built-in modules لل Python مكتوبة بال C بهدف السرعة مثلا او إضافة built-in types او عمل encapsulation لل C lib functions او System Calls او حتى إخفاء ال source code الخاص بيك

    المتطلبات: خبرة جيدة بال C و Python
    اول شئ بكل تأكيد هو إننا هنستخدم Python API/C وذلك بضم python.h لل project


    ملحوظة: قم بضم python.h قبل اى header اخر. جميل نبدأ ب Hello, World
    1- انشئ ملف helloMod.c
    2- اكتب التالى
    كود:
    #include <Python.h>
     
    static PyObject* hola(PyObject* self, PyObject* args)
    {
    
    
        if (!PyArg_ParseTuple(args, "", NULL))
            return NULL;
    
        printf("Hola!");
    
        Py_RETURN_NONE;
    }
    
    static PyMethodDef HolaMethods[] =
    {
         {"hola", hola, METH_VARARGS, "prints Hola\n"},
         {NULL, NULL, 0, NULL}
    };
    
    PyMODINIT_FUNC
    
    inithola(void)
    {
         (void) Py_InitModule("hola", HolaMethods);
    }
    نبدأ ب module بسيطة وهى hola هنشرح سطر سطر
    اولا نعمل include ل python api header كالتالى
    كود:
    #include <Python.h>
    اى Object فى Python تقدر تعرفه ك Pointer ل ب PyObject
    احنا الأول عايزين نعرف function بسيطة تطبع كلمة Hola!
    كود:
    static PyObject* hola(PyObject* self, PyObject* args)
    لاحظ self هو Pointer فى حال لو ال PyObject Class ودى هتكون ال method تبعه. لكن لو Function يبقة self هيكون NULL . عايزين يتم إستخدام ال Function كالتالى
    كود:
    >>> hola.hola()
    Hola!
    لاحظ شئ إن ال Function مش هتاخد اى argument و مش ليها return او ال Return ب NONE

    فالأول نختبر هل فى arguments اتباصت لل Function او لأ
    كود:
    if (!PyArg_ParseTuple(args, "", NULL))
            return NULL;
    PyArg_ParseTuple هى Function بتسخدم فى عمل Parse او تحليل لل Arguments وفيها بيتم تحويل ال Python Values ل C Values زى ماهنشوف فى مثال قادم.
    args هى ال arguments اللى هتتباصى لل Function
    هى بتعبر عن ال Data Type الخاص بال Argument مثلا s او i وهكذا
    s: String
    i: Integer
    .. etc
    NULL هنا بيعبر عن ال متغيرات اللى هتاخد القيم اللى اتباصت لل args -هنطلع عليها اكثر فى مثال قادم-
    كود:
       return NULL;
    للخروج مباشرة من تنفيذ ال Function
    بعد كدا نيجى لل ال Function هتعمله وهو طباعة كلمة Hola بإستخدام printf


    printf("Hola!");
    واخيرا زى ماقلنا اننا مش عايزين اى return من ال Function فهنعمل Py_RETURN_NONE
    كود:
        Py_RETURN_NONE;
    هنحتاج نعرف ال methodTable وهو عبارة عن array بتشمل معلومات عن ال Function زى الname, address وال Documentation الخاصة بيها وهكذا
    كود:
    static PyMethodDef HolaMethods[] =
    {
         {"hola", hola, METH_VARARGS, "prints Hola"},
         {NULL, NULL, 0, NULL}
    };
    اول field هو ال name الخاص بال function
    التانى هو ال function نفسها
    التالت بيعبر عن ان ال Arguments اللى هتتباصى هى Python-Level Arguments وغالبا بنستخدم METH_VARAGS
    الرابع هو الوصف الخاص بال function
    ونحجز المكان التانى فى ال Array ب
    كود:
    {NULL, NULL, 0, NULL}
    نعمل Initialize لل Module بتاعتنا كالتالى
    كود:
    PyMODINIT_FUNC
    inithola(void)
    {
         (void) Py_InitModule("hola", HolaMethods);
    }

    PyMODINIT_FUNC هى إختصار ل Python Module Initializer Function و فيها بيتم تجهيز ال Module
    بإستدعاء Py_InitModule وهى Function وهى اللى بتقوم بالتجهيز بالفعل وبتاخد 2Arguments
    1- اسم الModule
    2- ال Methods Table

    جميل جدا.. كدا كتبنا اول Module خاصة بينا!
    هنحتاج نضم ال Extension لل Python ولكن إزاى ؟


    بكل بساطة افتح ال Editor المفضل عندك وهنعمل setup script بال Python بإستخدام Distutils
    كود:
    from distutils.core import setup, Extension
     
    modExt = Extension('hola', sources = ['hola.c'])
     
    setup (name = 'HolaPackage',
            version = '1.0',
            description = 'Simple demo',
            ext_modules = [modExt])
    الخطوات سهلة وسلسة كالتالى:
    1- إستدعينا setup, Extension من Disutils.core
    2- عملنا Extension Object كالتالى
    كود:
    modExt = Extension('hola', sources = ['hola.c'])
    وفيه بنحدد ال source واسم الextension
    3- تجهيز ال setup script بإننا نسجل فيه إسم ال Package و الإصدار والوصف و ال extensions كالتالى

    كود:
    setup (name = 'HolaPackage',
            version = '1.0',
            description = 'Simple demo',
            ext_modules = [modExt])
    كل ماعليك هو
    كود:
    Python setup.py build
    وبعد كدا تعمل Install لل Package كالتالى
    كود:
    Python setup.py install

    نجرب ال Hola Module كالتالى
    1- اعمل اى Test Script وليكن HolaTest.py
    2- اعمل import ل hola Module كالتالى
    كود:
    import hola
    3- استدعى ال hola function كالتالى
    كود:
    hola.hola()
    #output:
    Hola!
    4- لنوضيح ال return الخاص بال Function اكتب
    كود:
    print hola.hola()
    #Output:
    Hola!
    None
    بعد ماطلعنا على الأساسيات نجرب نكتب module فيها function بتقبل argument ك name و age وتطبعهم و Function اخرى لحساب القيمة المطلقة لرقم وواحدة تقسم عددين وواحدة تعمل return ب Tuple, Dictionary
    الفكرة بإختصار:
    1- نعرف ال Functions
    2- نضمهم لل Methods Table
    3- نعمل Initialize لل Module
    4- نجهز ال setup script
    5- نعمل Build و Install لل Module
    6- نستخدم ال Module عن طريق TestScript مثلا كالتالى


    1- تعريف ال Functions

    ال Hola Function
    كود:
    static PyObject* hola(PyObject* self, PyObject* args)
    {
    
        const char* name;
        int age;
    
        if (!PyArg_ParseTuple(args, "si", &name, &age))
            return NULL;
    
        printf("Name: %s", name);
        printf("Age: %i", age);
    
    
        Py_RETURN_NONE;
    }
    كود:
     if (!PyArg_ParseTuple(args, "si", &name, &age))
    لاحظ إننا هنا توقعنا إن هيتباصى لل Function التالىs وهى string و i وهى integer
    وقمنا بإسناد هذه القيم ل name و age

    ملحوظة: انت لن تقوم بالتعديل على name فافضل تعريف إنه يكون const فيكون تعريفه كالتالى
    كود:
    const char* name;

    MyABS Function

    كود:
    static PyObject* myabs(PyObject* self, PyObject* args)
    {
    
        int number;
    
        if (!PyArg_ParseTuple(args, "i", &number))
            return NULL;
        
        if (number<0){
          number=-number;
        }
        return Py_BuildValue("i", number);
    
    }
    لاحظ اننا توقعنا إن هيتباصى لل Function التالى i وهو integer وبيعبر عن الرقم
    اسندنا القيمة الى number (التحويل من Python Value إلى C Value)

    ال Return لازم يكون عبارة عن Python Value (او PyObject) وهو ال Return Type الخاص بال myabs Function كما لاحظت، فبالتالى هنحتاج نحول من ال C Value إلى Python Value ودا هيتم عن طريق إستخدام Py_BuildValue
    وهنا تم تحديد إن هيتم عمل return ل i وهو Integer وقيمته مساوية ل number


    holaDict Function
    كود:
    static PyObject* holaDict(PyObject* self, PyObject* args)
    {
    
        const char* key;
        int value;
    
        if (!PyArg_ParseTuple(args, "si", &key, &value))
            return NULL;
    
        return Py_BuildValue("{s:i}", key, value); //Returns a Dict.
    }
    لاحظ ان بيتم إعادة Dictionary Object واحنا حددنا كدا بالجزئية دى{s:i}
    إذا حبيت تعمل return ب List فكل ماعليك هو إنك تعدل ال Format للتالى
    return Py_BuildValue("[s,i]", key, value); //Returns a List object
    وإذا حبيت تعمل return ب Tuple فكل ماعليك هو إنك تعد ال Format كالتالى (s,i)


    hola Tuple Function
    كود:
    static PyObject* holaTuple(PyObject* self, PyObject* args)
    {
        const char* name;
        int age;
    
    
        if (!PyArg_ParseTuple(args, "si", &name, &age))
            return NULL;
    
        return Py_BuildValue("(s,i)", name, age); //Returns a Tuple
    }
    divTwo Function
    كود:
    static PyObject* divTwo(PyObject* self, PyObject* args)
    {
    
        int first;
        int second;
        int result;
    
        if (!PyArg_ParseTuple(args, "ii", &first, &second))
            return NULL;
    
        printf("First: %i\n", first);
        printf("Second: %i\n", second);
        
        if(second==0){  //DivByZeroError!
           	PyErr_SetString(PyExc_ZeroDivisionError, "DivByZero");
      	return NULL; //Get out!
        }
        result = first/second;
    
        return Py_BuildValue("i", result);
    }
    إذا كان المقسوم عليه يساوى 0 يبقة فى Error! ونقدر نبلغ ال Interpreter بيه بإستخدامPyErr_SetString
    نوع ال Error هو PyExc_ZeroDivisionError وال message هتكون DivByZero


    2- الضم لل Methods Table كالتالى
    كود:
    static PyMethodDef SimpleModuleMethods[]=
    {
         {"hola", hola, METH_VARARGS, "prints name and age"},
         {"myabs", myabs, METH_VARARGS, "returns the abs of a number"},
         {"divTwo", divTwo, METH_VARARGS, "DIV 2 "},
         {"holaTuple", holaTuple, METH_VARARGS, "returns a tuple"},
         {"holaDict", holaDict, METH_VARARGS, "returns a dict"},
    
         {NULL, NULL, 0, NULL}
    };
    لاحظ إن آخر عنصر فى ال Array هو حاجز..

    3- عمل Initialize لل Module كالتالى بنستدعى فيها ال Py_InitModule Function كالتالى

    كود:
    PyMODINIT_FUNC
    
    initsimplemodule(void)
    {
         (void) Py_InitModule("simplemodule", SimpleModuleMethods);
    }
    4- ال Setup Script كالتالى
    كود:
    from distutils.core import setup, Extension
     
    modExt = Extension('simplemodule', sources = ['simplemodule.c'])
     
    setup (name = 'SimpleModPackage',
            version = '1.0',
            description = 'hola, myabs',
            ext_modules = [modExt])
    بنوضح فيه اسم ال Package والإصدار والوصف وال extension اللى بيشمل اسم ال module والsource
    5- عمل Build و Install كالتالى
    كود:
    python setup.py build
    python setup.py install
    6- عمل Test Script واختبار ال Module كالتالى
    كود:
    #!bin/python
    
    import simplemodule as sm
    
    sm.hola("Ahmed", 18)
    print sm.myabs(-10) #10
    print sm.myabs(7) #7
    print sm.holaDict("python", 1)
    print sm.holaTuple("ahmed", 999)
    print sm.divTwo(2, 0)
    #Output:
    Name: Ahmed
    Age: 18
    10
    7
    {'python': 1}
    ('ahmed', 999)
    First: 2
    Second: 0
    Traceback (most recent call last):
    File "C:\Python25\Projects\exten\smTest.py", line 10, in <module>
    print sm.divTwo(2, 0)
    ZeroDivisionError: DivByZero

    References:

    1- Extending Python
    2- Programming Python 3rd Edition

    Related:

    1- Style Guide for C Code
    2- SWIG
    3- CXX


    --Ahmed Youssef
    الملفات المرفقة
    Programming-Fr34ks[dot]NET
    Ma Weblog
    ابدأ بتعلم Python | Ruby
    كتاب البايثون متوافر الآن
    لا اتواجد بهذا المنتدى ... للإتصال

  • #2
    وإهداء ل صوفى وستورم وجراى
    شكرا ياولدي ^_^
    إخفاء ال source code الخاص بيك
    ليه يابني كده يابني ؟؟؟ بتشجع الناس علي قفل المصادر الحره !!!!
    اطالب برفد هذا العضو


    المتطلبات: خبرة جيدة بال C و Python
    تعديل

    خبره جيده بال c ولازم تكون spoiled programmer في ال Python
    BOOOF , I AM GONE
    Still , you gotta wait for my PRESENT :D
    C programming arabic Tutorial|Programming-fr34ks

    تعليق


    • #3
      اموت انا في المواضيع الدسمة اللي ماحدش بيفهم منها حاجة

      u r da [email protected] [email protected] ^_*
      V.I.P

      (وَاصْبِرْ فَإِنَّ اللَّهَ لَا يُضِيعُ أَجْرَ الْمُحْسِنِينَ)
      هود 115

      Linux is user-friendly, but it happens to be selective about its friends

      "احذر أن تكون مثل البقية تأخذ وﻻتعطي ، فلن يكون هناك مصادر تعليمية على الشبكة، ﻻأكثر الله من أمثالهم"


      مجتمع لينوكس العربي: وقف لله تعالى وصدقة جارية، فلا بارك الله في كل من يحاول الإساءة إليه في الظاهر أو في الخفاء...


      تعليق


      • #4
        شكرا على مرورك ياجماعة

        @St0rM:
        ليه يابني كده يابني ؟؟؟ بتشجع الناس علي قفل المصادر الحره !!!!
        لأ انا بوضح بس
        اهمد يابنى بلاش انت ال spoiled ال

        @Grey: الله يخليك ياجراى ومش بعد مسترتك يا حج
        Programming-Fr34ks[dot]NET
        Ma Weblog
        ابدأ بتعلم Python | Ruby
        كتاب البايثون متوافر الآن
        لا اتواجد بهذا المنتدى ... للإتصال

        تعليق

        يعمل...
        X