點擊進入項目python
思路是在C語言中提供實參,傳給python函數:linux
#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:
塊的用途是同樣的。git
/* 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); }
/* 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; }
編譯運行,github
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
這是個意義不大功能,只是展現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中,有以下效果bash
>>> import sample >>> def add(x,y): ... return x+y ... >>> sample.call_func(add,3,4) 7.0 >>>