cdef函数返回多个值的Cython异常传播



我有一个cdef函数返回一个(int, int)元组。我需要传播异常,因此必须为异常指定返回类型。由于我的函数从不返回负值,因此这可能是(-1, -1)。使用文档中指定的标准语法,我的函数看起来像

cdef (int, int) myFunction(int arg) except (-1, -1):
...

然而,当对上述函数进行cythonization时,我得到了错误

Not allowed in a constant expression

我知道我可以通过

打开每个函数调用后寻找异常
cdef (int, int) myFunction(int arg) except *:
...

但这对我来说似乎效率低下。

我如何传播异常与多个返回值的函数?

答案是:你不能,至少在Cython的cdef-tuples的当前版本中不能。

潜在的问题是,对于这样的元组,操作符==没有由Cython定义(这显然可以通过比较每个条目来完成-但在当前版本中没有定义)。

对于一个简单的cdef int myfun() except *来说,实际上并不是一个很大的性能冲击:

  • 如果结果不是-1,则几乎没有开销(仅与-1比较)。
  • 如果结果为-1,则使用PyErr_Occurred检查错误,这可能意味着相当大的开销(以上都是nogil块)
  • 可以通过except? X选择临界值X,从而最小化/优化PyErr_Occured调用的必要数量。

然而,如果Cython不知道类型的==操作符(如Cython的c元组),我们基本上处于cdef void myfun() except *情况,这意味着没有捷径,必须始终检查/调用PyErr_Occured


你可能会说==是为Cython的元组定义的,因为它被编译了。但是,如果您查看生成的代码,您将看到,为了进行比较,Cython的元组被转换为python元组。


我个人会首先选择except *,看看它是否真的具有可衡量的影响。因为cdef-function显然可以与python交互,所以增加一点可能不会有什么坏处。

如果是这样,最好的方法可能是更改函数的签名,例如
cdef  int myFunction(int arg, (int, int) *a) except -1:
...
return 0

即使感觉不那么流畅,但由于性能更好,这可能是值得的。

相关内容

  • 没有找到相关文章

最新更新