Internet & Web Application

Embedding Python in Another Application : ใช้ Python ร่วมกับภาษาอื่น

Python มีข้อดีในเรื่องลด How to programming (Imperative Programming) ไปสู่ What to programming (Declarative Programming) ทำให้นักวิทยาศาสตร์ นักวิจัย ต่างก็นิยมใช้ทดสอบแนวคิดที่นำเสนอในงานวิจัย เพราะสะดวก รวดเร็ว ไม่ต้องกังวลข้อผิดพลาด ว่าต้องเขียนโปรแกรมอย่างไร

แต่การนำไปใช้งานจริงนั้น คงไม่สะดวก และปลอดภัย (ลิกขสิทธิ์) นัก หากนำ Python script ไปใช้โดยตรง จึงจะดีกว่าหากสามารถนำ Python ไปใช้ร่วมกับภาษาอื่นได้ เช่น การใช้ร่วมกับภาษา C

เรียกใช้ Python ผ่านภาษา C ผ่าน Interpreter

– เขียนภาษา C ปรกติ แล้วเรียกใช้ Python

– เริ่มต้น program ใน C ด้วยการเรียก Py_Initialize() (Interpreter) แล้วจะสามารถเรียกใช้ Python ได้ตลอดทั้ง program

– ประมวลผล Python code ที่ไม่ต้องการ Input/Output (อย่างง่าย) ก็ใช้ PyRun_SimpleString() และ PyRun_SimpleFile()

#include <Python.h>

int
main
          (
          int argc
          , char *
          argv
          [])
{
  Py_Initialize
          (); // Start
          
  PyRun_SimpleString
          (
          "from time import time,ctime
          \n
          "
                     "print 'Today is',ctime(time())
          \n
          "
          ); // Can use 'PyRun_SimpleFile' either
  Py_Finalize
          (); // End
          
  return 0
          ;
}

– อยากดูตัวอย่าง สามารถหาได้ใน directory package Python: Demo/embed/

– กระบวนการที่เกี่ยวเนื่องคือ Convert data values from C to Python, Perform a function call to a Python interface routine using the converted values, and Convert the data values from the call from Python to C.

– ยกตัวอย่าง Code C “call.c” แบบง่าย ต่อไปนี้

#include <Python.h>

int
main
          (
          int argc
          , char *
          argv
          [])
{
    PyObject *
          pName
          , *
          pModule
          , *
          pDict
          , *
          pFunc
          ;
    PyObject *
          pArgs
          , *
          pValue
          ;
    int i
          ;

    if (
          argc < 3
          ) {
        fprintf
          (
          stderr
          ,
          "Usage: call pythonfile funcname [args]
          \n
          "
          );
        return 1
          ;
    }

    Py_Initialize
          ();
    // --- First part
            เตรียม Module ---
    pName = PyString_FromString
          ( 
          argv
          [
          1
          ] );
    /* Error checking of pName left out */

    pModule = PyImport_Import
          (
          pName
          );
    Py_DECREF
          (
          pName
          );
// ------------------
    if (
          pModule != NULL
          ) { 
 
        // --- Second part เตรียม Function ---
        pFunc = PyObject_GetAttrString
          (
          pModule
          , argv
          [
          2
          ]);
        /* pFunc is a new reference */

        if (
          pFunc && PyCallable_Check
          (
          pFunc
          )) {
            // --- Third part เตรียม Arguements ---
            pArgs = PyTuple_New
          (
          argc - 3
          );

for ( i = 0 ; i < argc - 3 ; ++ i ) {
pValue = PyInt_FromLong ( atoi ( argv [ i + 3 ])); if ( ! pValue ) { Py_DECREF ( pArgs ); Py_DECREF ( pModule ); fprintf ( stderr , "Cannot convert argument \n " ); return 1 ; } /* pValue reference stolen here: */
PyTuple_SetItem ( pArgs , i , pValue ); }
            // --- Forth part สั่ง Run !!! ---
            pValue = PyObject_CallObject
          (
          pFunc
          , pArgs
          );
            Py_DECREF
          (
          pArgs
          );
            // --- Fifth part ดูผล ---
            if (
          pValue != NULL
          ) {
                printf
          (
          "Result of call: %ld
          \n
          "
          , PyInt_AsLong
          (
          pValue
          ));
                Py_DECREF
          (
          pValue
          );
            }
            else {
                Py_DECREF
          (
          pFunc
          );
                Py_DECREF
          (
          pModule
          );
                PyErr_Print
          ();
                fprintf
          (
          stderr
          ,
          "Call failed
          \n
          "
          );
                return 1
          ;
            }
        }
        else {
            if (
          PyErr_Occurred
          ())
                PyErr_Print
          ();
            fprintf
          (
          stderr
          , "Cannot find function 
          \"
          %s
          \"\n
          "
          , argv
          [
          2
          ]);
        }
        Py_XDECREF
          (
          pFunc
          );
        Py_DECREF
          (
          pModule
          );
    }
    else {
        PyErr_Print
          ();
        fprintf
          (
          stderr
          , "Failed to load 
          \"
          %s
          \"\n
          "
          , argv
          [
          1
          ]);
        return 1
          ;
    }
    Py_Finalize
          ();
    return 0
          ;
}

– เพื่อเรียกใช้งาน multiply.py ผ่าน command line ดังนี้

$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6

– ส่วนสำหรับ multiply.py นั้น มี function multiply ทำหน้าที่คูณ 2 args ที่เข้ามา และ Return ค่ากลับไป

def multiply
          (
          a
          ,
          b
          )
          :
    print "Will compute"
          , a
          , "times"
          , b
    c = 0
    for i in range
          (
          0
          , a
          )
          :
        c = c + b
    return c

– ลองมาดูทีละส่วน จาก C code เริ่มจาก First part ที่ต้องการ Load Python module ชื่อตาม pName ซึ่งต้องเป็น Python String ทำให้เดือดร้อน ต้องขอความช่วยเหลือจาก PyString_FromString มาปรับเปลี่ยนให้

    // --- First part ---
    pName = PyString_FromString
          ( 
          argv
          [
          1
          ] );
    /* หากต้องการจรวจสอบให้ใส่ Code ในส่วนนี้ */

    pModule = PyImport_Import
          (
          pName
          );
    Py_DECREF
          (
          pName
          );
// ------------------

– จากนั้น หากทำการ Load Module “multiply.py” ได้สำเร็จ … ขั้นต่อมาคือ พยายามมองหา Function ที่ต้องการจะ Call (ชื่อ Function อยู่ใน argv[2])

pFunc = PyObject_GetAttrString
          (
          pModule
          , argv
          [
          2
          ]); // ตรวจสอบหา Obj. ใน Module
/* pFunc is a new reference */

if (
          pFunc && PyCallable_Check
          (
          pFunc
          )) { // สามารถทำงานได้หากมีชื่อ Func. & สามารถเรียกใช้ได้
    ... ใช้งาน ...
}
Py_XDECREF
          (
          pFunc
          ); // ประหยัดหน่วยความจำ 

– การเรียกใช้งาน ก็ผ่านค่า pFunc และ pArgs ที่ได้เตรียมไว้แล้วเข้าไป ซึ่งจะได้ pValue เป็นค่า return มาให้

pValue = PyObject_CallObject
          (
          pFunc
          , pArgs
          );

– ค่าจากการประมวลผลอยู่ใน pValue สามารถใช้ API ที่เตรียมไว้ Convert มาเป็น C เพื่อใช้งานต่อไปได้

– ข้อสังเกต Py_XDECREF : ใช้ลดจำนวนการอ้างถึง Python object ต่างๆ ซึ่งหาก interpreter พบว่า การอ้างอิง ถึงเป็น 0 จะให้ Garbage Collector จัดการกำจัดทิ้งจากหน่วยความจำ

หาก Python code ที่กำลังทำงานอยู่ต้องการ Callback กลับมาล่ะ ?

– สำหรับ Code Python ที่กำลังทำงานอยู่ หากต้องการเชื่อมต่อกับ Process ของ C .. จะทำอย่างไร ?


อ้างอิงจาก

http://docs.python.org/extending/embedding.html

http://www.linuxjournal.com/article/8497

http://en.wikipedia.org/wiki/Declarative_programming

http://docs.python.org/c-api/index.html#c-api-index


Del.icio.us :
Technorati :

Advertisements
มาตรฐาน

ใส่ความเห็น

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / เปลี่ยนแปลง )

Twitter picture

You are commenting using your Twitter account. Log Out / เปลี่ยนแปลง )

Facebook photo

You are commenting using your Facebook account. Log Out / เปลี่ยนแปลง )

Google+ photo

You are commenting using your Google+ account. Log Out / เปลี่ยนแปลง )

Connecting to %s