基于C-exit代码捕获ctypes中的exception
我正在使用ctypes
调用Python/numpy
中用C
编写的共享库。 这很有效,但是,当在C
使用exit
函数时, iPython
会出现一些意外结果。
请考虑以下示例,其中数组“A”的第一项在C
修改。 如果值为负,则应引发exception。
C
代码:
#include #include #include extern void cfun(double* A) { // raise exception if A[0]<0.0 if ( A[0]<0.0 ) { printf("Negative value of A[0] encountered\n"); exit(1); } // change "A[0]" to it's square A[0] = pow(A[0],2); }
哪个是使用编译的
gcc -c -fPIC fun.c gcc -shared -o test.so fun.o
包装Python
-code:
import numpy as np import ctypes # include shared library lib = ctypes.CDLL("./test.so") # link to C-program, including input-typing cfun = lib.cfun cfun.restype = None cfun.argtypes = [ np.ctypeslib.ndpointer(ctypes.c_double,flags="C_CONTIGUOUS") ] # simple example A = np.arange((5),dtype='float')+2. cfun(A) print A # expected output: [ 4. 3. 4. 5. 6.] # simple example A[0] = -10.0 cfun(A) print A # expected output: exception, no output from "print A"
当我从命令行运行此代码时,程序会执行它应有的操作。 输出:
[ 4. 3. 4. 5. 6.] Negative value of A[0] encountered
但是当我从iPython
运行python函数时
- 想要的行为是引发某种exception,
- 当前的行为是,当遇到错误时,
iPython
也存在。
我相信最优雅的解决方案是引入一个错误流作为(返回)参数来表示成功或失败。 但是我真的想避免这种情况。 我使用了广泛的C
代码。 引入错误流会使所有函数之间的依赖性过度复杂化。
请帮忙!
exit
调用系统的exit函数并终止正在运行的进程,在你的情况下是ipython。 在C中完成error handling的方法是设置一些全局错误变量并返回状态标志
#include char *error_string; extern char* get_error_string() { return error_string; } extern int cfun(double* A) { // raise exception if A[0]<0.0 if ( A[0]<0.0 ) { error_string = "Negative value of A[0] encountered\n"; return -1; } // change "A[0]" to it's square A[0] = pow(A[0],2); return 0; }
并在Python中测试错误:
import numpy as np import ctypes # include shared library lib = ctypes.CDLL("./test.so") # link to C-program, including input-typing get_error = lib.get_error get_error.restype = ctypes.c_char_p get_error.argtypes = [] def c_error_wrapper(func): def method(*args): status = func(*args) if status<0: raise RuntimeError(get_error()) return method # link to C-program, including input-typing cfun = lib.cfun cfun.restype = ctypes.c_int cfun.argtypes = [ np.ctypeslib.ndpointer(ctypes.c_double,flags="C_CONTIGUOUS") ] cfun = c_error_wrapper(cfun) # simple example A = np.arange((5),dtype='float')+2. cfun(A) print A # expected output: [ 4. 3. 4. 5. 6.] # simple example A[0] = -10.0 cfun(A) print A # expected output: exception, no output from "print A"