『Python CoolBook』C擴充庫_其六_從C語言中調用Python代碼

來源:互聯網
上載者:User

標籤:bsp   檢查   self   inter   obj   book   部分   字串類   直接   

一、C語言運行pyfun的PyObject對象

思路是在C語言中提供實參,傳給python函數:

  • 擷取py函數對象(PyObject),函數參數(C類型)
  • 擷取GIL(PyGILState_Ensure)
  • 確保fun對象可調用
  • 參數轉換為python對應類型(Py_BuildValue)
  • 調用python函數(PyObject_Call)
  • 確定調用無異常
  • 檢查傳回值
  • 釋放GIL(PyGILState_Release)
  • 異常處理
#include "Python.h"/* Execute func(x,y) in the Python interpreter.  The   arguments and return result of the function must   be Python floats */double call_func(PyObject *func, double x, double y) {  PyObject *args;  PyObject *kwargs;  PyObject *result = 0;  double retval;  /* Make sure we own the GIL */  PyGILState_STATE state = PyGILState_Ensure();  /* Verify that func is a proper callable */  /* 你必須先有一個表示你將要調用的Python可調用對象。 這可以是一個函數、     類、方法、內建方法或其他任意實現了 __call__() 操作的東西。 為了確     保是可調用的,可以像下面的代碼這樣利用 PyCallable_Check() 做檢查 */  if (!PyCallable_Check(func)) {    fprintf(stderr,"call_func: expected a callable\n");    goto fail;  }  /* Build arguments */  /* 使用 Py_BuildValue()構建參數元組或字典 */  args = Py_BuildValue("(dd)", x, y);  kwargs = NULL;  /* Call the function */  /* 使用 PyObject_Call(),傳一個可調用對象給它、一個參數元組     和一個可選的關鍵字字典。     如果沒有關鍵字參數,傳遞NULL */  result = PyObject_Call(func, args, kwargs);  /* 需要確保使用了 Py_DECREF() 或者 Py_XDECREF() 清理參數。      第二個函數相對安全點,因為它允許傳遞NULL指標(直接忽略它),      這也是為什麼我們使用它來清理可選的關鍵字參數。 */  Py_DECREF(args);  Py_XDECREF(kwargs);  /* Check for Python exceptions (if any) */  /* 調用萬Python函數之後,用PyErr_Occurred() 函數檢查是否     有異常發生 */  if (PyErr_Occurred()) {    PyErr_Print();    goto fail;  }  /* Verify the result is a float object */  if (!PyFloat_Check(result)) {    fprintf(stderr,"call_func: callable didn‘t return a float\n");    goto fail;  }  /* Create the return value */  retval = PyFloat_AsDouble(result);  Py_DECREF(result);  /* Restore previous GIL state and return */  PyGILState_Release(state);  return retval;fail:  Py_XDECREF(result);  PyGILState_Release(state);  abort();   // Change to something more appropriate}

 要注意的是每一個 PyGILState_Ensure() 調用必須跟著一個匹配的 PyGILState_Release() 調用——即便有錯誤發生。 在這裡,我們使用一個 goto 語句看上去是個可怕的設計, 但是實際上我們使用它來講控制權轉移給一個普通的exit塊來執行相應的操作。 在 fail: 標籤後面的代碼和Python的 fianl: 塊的用途是一樣的。

二、使用模組名和方法名擷取pyfun的PyObject對象
  • 擷取模組名字串,方法名字串
  • 模組名轉化為python的字串類型(PyUnicode_FromString)
  • 類比python的import行為(PyImport_Import),這是因為我們想經由python的邏輯擷取函數
  • 由python的module擷取方法(PyObject_GetAttrString),這個API擷取方法使用的是C字串
  • 返回方法,時python的物件類型
/* Load a symbol from a module */PyObject *import_name(const char *modname, const char *symbol) {  PyObject *u_name, *module;  u_name = PyUnicode_FromString(modname);  module = PyImport_Import(u_name);  Py_DECREF(u_name);  return PyObject_GetAttrString(module, symbol);}
三、C類比Python運行
  • 初始化python環境(Py_Initialize)
  • 匯入模組擷取方法(見本文第二部分)為PyObject
  • 調用方法PyObject(見本文第一部分)
  • 結束python環境(Py_Finalize)
/* Simple embedding example */int main() {  PyObject *pow_func;  double x;  Py_Initialize();  /* Get a reference to the math.pow function */  pow_func = import_name("math","pow");  /* Call it using our call_func() code */  for (x = 0.0; x < 10.0; x += 0.1) {    printf("%0.2f %0.2f\n", x, call_func(pow_func,x,2.0));  }  /* Done */  Py_DECREF(pow_func);  Py_Finalize();  return 0;}

編譯運行,

gcc -g embed.c -I/home/hellcat/anaconda3/include/python3.6m           -L/home/hellcat/anaconda3/lib/python3.6/config-3.6m-x86_64-linux-gnu -lpython3.6m
四、將可調用PyObject用C重新封裝調用

這是個意義不大功能,只是展示C API中PyObject本質運行邏輯——PyObject可以代指任何Python中的對象,這裡是它接收函數的例子:

/* Extension function for testing the C-Python callback */static PyObject *py_call_func(PyObject *self, PyObject *args) {  PyObject *func;  double x, y, result;  if (!PyArg_ParseTuple(args,"Odd", &func,&x,&y)) {    return NULL;  }  result = call_func(func, x, y);  return Py_BuildValue("d", result);}

把它寫到前一節中的pysample.c中,有如下效果

>>> import sample>>> def add(x,y):...     return x+y...>>> sample.call_func(add,3,4)7.0>>>

 

『Python CoolBook』C擴充庫_其六_從C語言中調用Python代碼

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.