2

cdef函数的签名中:

cdef const unsigned char[:, :] my_fn(input) except <????> :

我要放<????>什么?

如果我正确理解了文档,那么指定异常类型对于将异常传播到 Python 堆栈是必要的。

我尝试了一些[b'\x00']空的 Cython 数组,但没有任何效果。

4

1 回答 1

3

坏消息:你做不到。好消息:您不必这样做!

仅当函数返回一个、一个枚举、一个浮点数或一个指针except <xxx>时才可能使用 with 的语法- 基本上是在 C中比较有意义的东西。cdefint==

类型化的内存视图是一个 Python 对象,当返回的对象是空指针时,它有一个内置的方式来发出错误信号。因此,您不必定义异常值,因为它已经定义了!

例如:

%%cython
cdef int[:] worker(int[:] memview, int index):
    memview[index]=10 
    return memview

def runit(index):
    cdef int mem[4]
    print(worker(mem,index))

现在

runit(4)   #4 -> out of bounds
print("I still run")

不打印“我仍在运行”,因为传播了越界异常。

对于不是 Python 对象的返回值,情况并非如此,例如int

%%cython
cdef int worker(int[:] memview, int index):
    return memview[index]

现在:

runit(4)   #4 -> out of bounds
print("I still run")

打印“0”和“我仍在运行”,因为错误没有传播。我们可以选择一个异常值,例如-1,通过 return-value=-1 传播错误:

%%cython
cdef int worker(int[:] memview, int index) except -1:
    return memview[index]

现在,不再打印“我还在跑步”。

但是,有时没有好的异常值,例如因为memview可以包含任何整数值:

%%cython
cdef int worker(int[:] memview, int index) except -1:
    return memview[index]

def runit(index):
    cdef int mem[4]
    mem[0]=-1
    print(worker(mem, index))

现在,跑步

runit(0)
print("I still run")

以虚假错误结束:

SystemError:返回 NULL 而不设置错误

解决方案是使用

cdef int worker(int[:] memview, int index) except *

runit(0)对和有正确的行为runit(4)

那么与使用except *相比,使用成本是except -1多少?它们并不高:

如果返回值是-1(这是默认的“异常”值),那么我们知道可能发生了错误(这只是一种可能性而不是确定性)并检查 via PyErr_Occurred(),是否真的如此。

正如评论中提到的@DavidW,也可以使用except? -1它具有更易于阅读和理解的优点。有趣的是,这会产生与 相同的 C 代码except *,因为默认的错误值是-1!

但是,except?- 语法允许我们选择我们必须为其支付开销的函数结果PyErr_Occurred()。例如,如果我们知道结果-1经常发生而且-2几乎从不发生,那么我们可以使用except? -2andPyErr_Occured()仅在函数的结果为 时才被检查-2,这意味着几乎从不(在这种情况下except *会经常检查- 每次-1都返回)。

于 2018-06-04T18:58:52.567 回答