簡體   English   中英

使用 python 函數作為參數調用 Cython(C) 函數

[英]Calling Cython(C) functions with python functions as argument

我想將本地定義的 python 函數與 gsl 庫集成。 為此,我用 Cython 實現了以下代碼(Gauss-Legendre 正交示例):

px文件:

cdef extern from "gsl/gsl_math.h":
ctypedef struct gsl_function:
double (* function) (double x, void * params) nogil
void * params

cdef extern from "gsl/gsl_integration.h":
gsl_integration_glfixed_table * gsl_integration_glfixed_table_alloc(size_t n) nogil 
double gsl_integration_glfixed(gsl_function *f, double a, double b, gsl_integration_glfixed_table * t) nogil
void  gsl_integration_glfixed_table_free(gsl_integration_glfixed_table *t) nogil 

cdef double int_gsl_GaussLegendre(double func(double, void *) nogil, void * p, double xmin, double xmax) nogil

和 pyx 文件:

cdef size_t size_GL=1000

cdef double int_gsl_GaussLegendre(double func(double, void *) nogil, void * p, double xmin, double xmax) nogil:
cdef double result, error;
cdef gsl_integration_glfixed_table * W 
cdef gsl_function F
W = gsl_integration_glfixed_table_alloc(size_GL)
F.function = func
F.params = p
result = gsl_integration_glfixed(&F, xmin, xmax, W)    
gsl_integration_glfixed_table_free(W)
return result

此代碼適用於在我的 Cython 代碼中聲明的任何 C function。 當然,當我將 python function 作為參數傳遞時,這將失敗。我在 python 中的腳本:

def gsl_integral(py_func, xmin, xmax, args=()):
cdef size_t sizep = <int>(args.size)
cdef double[:] params = np.empty(sizep, dtype=np.double)
for i in range(0,sizep):
    params[i]=args[i]
cdef gsl_function F
F.function = py_func
F.params = params

返回:“無法將 Python object 轉換為‘double (*)(double, void *) nogil’”

如果我改用:

def gsl_integral(py_func, xmin, xmax, args=()):
cdef size_t sizep = <int>(args.size)
cdef double[:] params = np.empty(sizep, dtype=np.double)
for i in range(0,sizep):
    params[i]=args[i]
cdef gsl_function F
F.function = <double *>py_func
F.params = params

返回:“Python 對象不能轉換為原始類型的指針”

我已經看到我可以將我的 cython function 包裝成 class( 通過 c function 作為 cython 中 python function 的參數),但我不太確定在這種情況下如何工作我。)作為一種解決方法,我一直將兩個數組 x 和 f(x) 傳遞給 Cython,后者用我的本地 python f 進行估計,以便定義一個我可以稍后集成的 gsl 樣條,但這並不優雅全部。 還有其他方法嗎? 我想在沒有 GIL 的情況下使用 GSL 集成

非常感謝,羅曼

您的基本前提存在一些基本問題:

  • C function pointers do not have any state. Python callable objects do have state. Therefore, C function pointers do not have space to store the information required to call a Python function.
  • 如果你正在調用一個 Python 可調用 object,你不能釋放 GIL,因為你必須有 GIL 來執行那個 object。

此答案概述了您的選項(C++ std::function選項不適用於此處)。 基本上你可以

  • 使用ctypes從 Python function 生成一個 function 指針(它在運行時通過 hacky 代碼生成來實現——這在標准 C 中是不可能的),
  • 或者編寫一個帶有適當簽名的cdef function 作為 function 指針傳遞,並將您的 Python 可調用傳遞給它作為void*參數的一部分。

我推薦后者,但兩者都不是很好的選擇。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM