Exception handling Cython:返回类型化memoryview的函数的异常类型

Exception handling Cython:返回类型化memoryview的函数的异常类型,exception-handling,cython,typed-memory-views,Exception Handling,Cython,Typed Memory Views,在函数的cdef签名中: cdef const unsigned char[:, :] my_fn(input) except <????> : cdef const unsigned char[:,:]my_fn(输入)除了: 我应该在中输入什么 如果我理解正确,指定异常类型是异常向上传播到Python堆栈所必需的 我尝试了[b'\x00']和空的Cython数组,但都不起作用 坏消息:你做不到。好消息:你不必这么做 只有当cdef函数返回一个int、一个枚举、一个浮点或一个指

在函数的
cdef
签名中:

cdef const unsigned char[:, :] my_fn(input) except <????> :
cdef const unsigned char[:,:]my_fn(输入)除了:
我应该在
中输入什么

如果我理解正确,指定异常类型是异常向上传播到Python堆栈所必需的


我尝试了
[b'\x00']
和空的Cython数组,但都不起作用

坏消息:你做不到。好消息:你不必这么做

只有当
cdef
函数返回一个
int
、一个枚举、一个浮点或一个指针时,才可能使用
except
语法-基本上,在C中通过
=
进行比较是有意义的

类型化内存视图是一个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
,以便通过返回值=-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-1
相比,使用
except*
的成本是多少呢?它们并不是很高:

如果返回值为
-1
(这是默认的“异常”值),则我们知道可能发生了错误(这只是一种可能性而不是确定性),并通过
PyErr_occurrent()
检查是否真的发生了错误

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


但是,
except?
-语法允许我们选择函数结果,我们必须为此支付
PyErr\u occurrent()
的开销。例如,如果我们知道结果
-1
经常出现,而
-2
几乎从不出现,那么我们可以使用
除了-只有当函数的结果是
-2
时,才会检查2
PyErr\u occurrend()
,这意味着几乎永远不会检查(在
除外*
的情况下,会经常检查-每次返回
-1

除外-1
表示-1可能是错误(但不是必需的)@DavidW谢谢你的提示!我已经相应地更新了我的答案。另一种方法是通过引用传入现在的返回值,而不是返回一个表示错误代码的int。