سفارش تبلیغ
صبا ویژن

آموزش افزونه نویسی برای پایتون با زبان C

امروز با مقاله دیگری از سری مقاله های آموزش پایتون همراه شما هستیم، در این مقاله میخواهیم چگونگی افزونه نویسی در پایتون به کمک کدهای زبان C را مورد بررسی قرار دهیم..

به منظور نوشتن افزونه های اختصاصی جهت استفاده در اسکریپت های پایتون و اپلیکیشن های خود، لازم است به فایل های header پایتون دسترسی داشته باشید.در دستگاه هایی که سیستم عامل Unix بر روی آن نصب است، می بایست یک پکیج مختص توسعه دهنده (developer-specific) نظیر python2.5-dev را نصب نمایید.

کاربران ویندوز این فایل های header را به هنگام استفاده از binary Python installer به صورت یک پکیج دریافت می کنند. علاوه بر آن، برای درک مفاهیم این مبحث و نوشتن افزونه های اختصاصی خود جهت استفاده در اسکریپت های پایتون، لازم است آشنایی در سطح پیشرفته با زبان های C یا ++C داشته باشید.

آموزش Python : اولین نمونه از افزونه اختصاصی Python

کد ماژول و افزونه های پایتون، بایستی مانند زیر در چهار بخش سازمان دهی شود:

  • فایل header با اسم و پسوند Python.h.
  • توابع C که می خواهید به عنوان interface و الگوی پیاده سازی ماژول اختصاصی خود در اختیار توسعه دهنده قرار دهید.
  • یک جدول که اسم توابع اختصاصی شما را به توابع C داخل افزونه (کتابخانه یا ماژول) نگاشت می کند (method mapping table).
  • یک تابع سازنده جهت مقداردهی اولیه و نمونه سازی از کلاس (initialization function).

فایل Python.h

لازم است فایل Python.h را داخل فایلی که کدهای C شما را دربرمی گیرد (source file) قید نمایید. بدین وسیله شما به توابع کتابخانه ای درون ساخته ی پایتون (internal Python API) که برای ادغام و معرفی ماژول مورد نظر در interpreter (hook کردن کد ماژول شما در مفسر) بکار می رود، دسترسی خواهید داشت. لازم است Python.h را قبل از هر فایل header مورد نیاز دیگری لحاظ نمایید. 

توابع C

اسم متد، نوع و تعداد پارامترهای ورودی (Signature) توابع اختصاصی شما و پیاده سازی آن، بایستی بر اساس یکی از الگوهای زیر انجام شود:

static PyObject *MyFunction( PyObject *self, PyObject *args );
static PyObject *MyFunctionWithKeywords(PyObject *self,
                                 PyObject *args,
                                 PyObject *kw);
static PyObject *MyFunctionWithNoArgs( PyObject *self );

هر یک از متدهای اعلان شده ی فوق، در خروجی خود یک آبجکت Python برمی گرداند. در پایتون مفهومی به نام تابع void (تابعی که خروجی ندارد یا مقداری را برنمی گرداند) وجود ندارد. اگر شما نمی خواهید که توابع مقدار خروجی داشته باشند، لازم است مقدار None را بازگردانی نمایید. header های پایتون یک macro (خط دستور) به نام Py_RETURN_NONE در خود به صورت از پیش تعریف شده دارند که این کار را انجام می دهند.

از آنجایی که اسم توابع C هیچگاه خارج از ماژول/افزونه قابل مشاهده و دسترسی نیستند، شما می توانید هر اسمی برای متدهای اختصاصی خود انتخاب کنید. لازم به ذکر است که این توابع با کلیدواژه ی static تعریف می شوند. اسم توابع C معمولا از ترکیبی از اسم ماژول و متد مورد نظر تشکیل می شود. در زیر نمونه ای را مشاهده می کنید:

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

کد حاضر یک تابع Python به نام func را تعریف می کند که داخل افزونه ی module کپسوله سازی شده است. حال شما به این توابع C داخل جدول نگاشت متد (method table) Pointer و اشاره گر تعریف می کنید که در بخش بعدی کد برنامه ی شما انجام می شود. 

آموزش برنامه نویسی پایتون : جدول نگاشت توابع

این جدول نگاشت متد (method table) یک آرایه ی ساده از structure های PyMethodDef است (PyMethodDef یک مدل برای تعریف متد است). این structure ساختاری مشابه زیر دارد:

struct PyMethodDef {
   char *ml_name;
   PyCFunction ml_meth;
   int ml_flags;
   char *ml_doc;
};

در زیر هر یک از اعضای این ساختار شرح داده اند:

  • فیلد ml_name : اسم تابع پایتون.
  • فیلد ml_meth : آدرس تابعی که هر یک از signature های نام برده در بخش قبلی را دارا می باشد.
  • فیلد ml_flags : این فیلد به مفسر پایتون اعلان می کند که فیلد دوم (ml_meth) کدام یک از signature های نام برده را اتخاذ می کند :
  1. این flag معمولا مقداری از METH_VARARGS دارد.
  2. اگر می خواهید آرگومان های کلیدواژه ای را در تابع تزریق نمایید، این flag می تواند OR بیتی با METH_KEYWORDS را شامل شود.
  3. این flag همچنین می تواند مقدار METH_NOARGS را داشته باشد، بدین معنی که هیچ پارامتری به تابع فرستاده نمی شود.
  • فیلد ml_doc : این docstring (رشته یا comment ای که توضیحی درباره ی کارایی تابع می دهد) تابع است. اگر برنامه نویس comment ای برای تابع تنظیم نکند، در آن صورت مقدار آن NULL خواهد بود.

این جدول بایستی با یک sentinel که از NULL و 0 برای اعضای مرتبط تشکیل شده، خاتمه یابد.

مثال :

برای متد اعلان شده در بالا، از جدول نگاشت تابع (method mapping table) زیر استفاده می کنیم:

static PyMethodDef module_methods[ ] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

آموزش زبان پایتون : تابع مقداردهی اولیه (initModule)

آخرین بخش ماژول یا افزونه ی اختصاصی شما بایستی تابع مقداردهنده ی اولیه (initialization function) را شامل شود. این تابع را مفسر پایتون زمانی که ماژول در حافظه بارگذاری می شود، فرامی خواند. لازم است اسم این تابع initModule انتخاب شود (Module اسم ماژول و init اسم خود تابع می باشد).

تابع مقداردهنده ی اولیه بایستی از کتابخانه که می نویسید export و خروجی گرفته شده باشد. header های Python با اعلان دستور PyMODINIT_FUNC امکان انجام این کار را در محیطی که اسکریپت ها در آن کامپایل می شوند را فراهم می آورد. کافی است به هنگام تعریف تابع مورد نظر از آن استفاده نمایید.

تابع مقداردهنده ی اولیه ی زبان C شما دارای ساختار کلی زیر می باشد:

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

در زیر شرح هر یک از پارامترهای تابع Py_InitModule3 را به تفصیل مشاهده می کنید:

  • پارامتر func : تابعی است که قرار است export و به اصطلاح خروجی گرفته شود.
  • پارامتر module_methods : اسم جدول نگاشت تابع (mapping table) که در بالا به آن اشاره شد.
  • پارامتر docstring : این پارامتر همان رشته ی متنی و comment ای است که جهت ارائه ی توضیح درباره ی قابلیت تابع در افزونه ی اختصاصی درج می شود.

در زیر تمامی بخش های تشکیل دهنده یک افزونه استاندارد را یکجا مشاهده می کنید:

#include < python.h>
static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}
static PyMethodDef module_methods[ ] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};
PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}
< /python.h>

مثال :

نمونه کاربردی که کلیه مفاهیم فوق را به صورت عملی بکار می برد را در زیر مشاهده می کنید:

#include < python.h>
static PyObject* helloworld(PyObject* self)
{
    return Py_BuildValue("s", "Hello, Python extensions!!");
}
static char helloworld_docs[ ] =
    "helloworld( ): Any message you want to put here!!\n"
static PyMethodDef helloworld_funcs[ ] = {
    {"helloworld", (PyCFunction)helloworld, 
     METH_NOARGS, helloworld_docs},
    {NULL}
};
void inithelloworld(void)
{
    Py_InitModule3("helloworld", helloworld_funcs,
                   "Extension module example!");
}
< /python.h>

دستور Py_BuildValue در مثال بالا، یک مقدار Python را build یا کامپایل می کند. کد مورد نظر را داخل فایل hello.c ذخیره نمایید. در زیر با نحوه ی کامپایل و نصب ماژول که از اسکریپت پایتون فراخوانی می شود، را خواهید آموخت.

کامپایل و نصب افزونه ها (build)

پکیج distutils توزیع و نصب ماژول های پایتون، خواه ماژول های اصلی و خالص خود پایوتن باشد خواه ماژول های اختصاصی و تنظیم شده توسط توسعه دهنده، را با روشی استاندارد بسیار آسان می سازد. ماژول ها در همان قالب اولیه (source form) توزیع شده و در اختیار برنامه نویس قرار می گیرد. برنامه نویس سپس ماژول مورد نظر را با فراخوانی اسکریپت نصب (setup script) به نام setup.py ، نصب می نماید.

جهت نصب ماژول ذکر شده در بالا، بایستی اسکریپت setup.py را آماده نموده و به روش زیر اجرا نمایید:

from distutils.core import setup, Extension
setup(name="helloworld", version="1.0",  \
      ext_modules=[Extension("helloworld", ["hello.c"])])

اکنون با فراخوانی دستور زیر، تمامی مراحل لازم نظیر کامپایل و آماده سازی (linking & compilation) کد را انجام دهید. کد زیر کلیه ی مراحل مورد نیاز کامپایل و لینک ماژول با کامپایلر، دستورات linker و flag های مناسب را انجام داده، متعاقبا خروجی (.dll) را در پوشه ی مربوطه جایگذاری (کپی) می کند.

$ python setup.py install

در سیستم های مبتنی بر Unix، لازم است این دستور را با حساب کاربری root اجرا نمایید تا امکان یا مجوز درج داده در پوشه ی site-packages را داشته باشید. در سیستم عامل ویندوز لازم به انجام این کار نیست.

 

با دیگر آموزش های ما در زمینه آموزش پایتون و دیگر زبان های برنامه نویسی همراه ما باشید...