Cython:返回类型化内存视图的函数的异常类型
Cython: exception type for a function returning a typed memoryview
在函数的 cdef
签名中:
cdef const unsigned char[:, :] my_fn(input) except <????> :
我应该在 <????>
中输入什么?
如果我对 documentation 的理解正确,则必须指定异常类型才能将异常向上传播到 Python 堆栈。
我尝试了 [b'\x00']
和空 Cython 数组,none 有效。
坏消息:你做不到。好消息:您不必这样做!
只有当 cdef
函数 return 是一个 int
、一个枚举、一个浮点数或一个指针时,except <xxx>
的语法才是可能的——基本上在 C.
中通过 ==
进行比较是有意义的
类型化内存视图是一个 Python 对象,当 returned 对象是空指针时,它有一个内置的方式来发出错误信号。因此,您不必定义异常值,因为它已经被定义了!
例如:
%%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")
不打印 "I still run" 因为越界异常被传播。
return 值不是 Python 对象,例如 int
:
%%cython
cdef int worker(int[:] memview, int index):
return memview[index]
现在:
runit(4) #4 -> out of bounds
print("I still run")
打印“0”和 "I still run",因为错误没有传播。我们可以选择一个特殊值,例如 -1
,这样错误就会通过 return-value=-1:
传播
%%cython
cdef int worker(int[:] memview, int index) except -1:
return memview[index]
现在,不再打印"I still run"。
然而,有时并没有很好的异常值,例如因为 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: returned NULL without setting an error
解决方法是使用
cdef int worker(int[:] memview, int index) except *
对 runit(0)
和 runit(4)
具有正确的行为。
那么与 except -1
相比,使用 except *
的成本是多少?他们不是真的高:
如果 returned 值是 -1
(这是默认的 "exceptional" 值),那么我们知道可能发生了错误(这只是一种可能性,而不是确定性)并通过 PyErr_Occurred()
检查是否真的如此。
正如@DavidW 在评论中提到的,也可以使用 except? -1
,其优点是更易于阅读和理解。有趣的是,这会产生与 except *
相同的 C 代码,因为默认错误值是 -1
!
然而,except?
语法允许我们选择我们必须支付PyErr_Occurred()
开销的函数结果。例如,如果我们知道结果 -1
经常出现而 -2
几乎从不出现,那么我们可以使用 except? -2
并且 PyErr_Occured()
仅在结果出现时才被检查函数的参数是 -2
,这意味着几乎从不(在 except *
的情况下,它会经常被检查——每次 -1
被 returned)。
在函数的 cdef
签名中:
cdef const unsigned char[:, :] my_fn(input) except <????> :
我应该在 <????>
中输入什么?
如果我对 documentation 的理解正确,则必须指定异常类型才能将异常向上传播到 Python 堆栈。
我尝试了 [b'\x00']
和空 Cython 数组,none 有效。
坏消息:你做不到。好消息:您不必这样做!
只有当 cdef
函数 return 是一个 int
、一个枚举、一个浮点数或一个指针时,except <xxx>
的语法才是可能的——基本上在 C.
==
进行比较是有意义的
类型化内存视图是一个 Python 对象,当 returned 对象是空指针时,它有一个内置的方式来发出错误信号。因此,您不必定义异常值,因为它已经被定义了!
例如:
%%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")
不打印 "I still run" 因为越界异常被传播。
return 值不是 Python 对象,例如 int
:
%%cython
cdef int worker(int[:] memview, int index):
return memview[index]
现在:
runit(4) #4 -> out of bounds
print("I still run")
打印“0”和 "I still run",因为错误没有传播。我们可以选择一个特殊值,例如 -1
,这样错误就会通过 return-value=-1:
%%cython
cdef int worker(int[:] memview, int index) except -1:
return memview[index]
现在,不再打印"I still run"。
然而,有时并没有很好的异常值,例如因为 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: returned NULL without setting an error
解决方法是使用
cdef int worker(int[:] memview, int index) except *
对 runit(0)
和 runit(4)
具有正确的行为。
那么与 except -1
相比,使用 except *
的成本是多少?他们不是真的高:
如果 returned 值是 -1
(这是默认的 "exceptional" 值),那么我们知道可能发生了错误(这只是一种可能性,而不是确定性)并通过 PyErr_Occurred()
检查是否真的如此。
正如@DavidW 在评论中提到的,也可以使用 except? -1
,其优点是更易于阅读和理解。有趣的是,这会产生与 except *
相同的 C 代码,因为默认错误值是 -1
!
然而,except?
语法允许我们选择我们必须支付PyErr_Occurred()
开销的函数结果。例如,如果我们知道结果 -1
经常出现而 -2
几乎从不出现,那么我们可以使用 except? -2
并且 PyErr_Occured()
仅在结果出现时才被检查函数的参数是 -2
,这意味着几乎从不(在 except *
的情况下,它会经常被检查——每次 -1
被 returned)。