返回多个值的 cdef 函数的 Cython 异常传播
Cython exception propagation for cdef functions returning multiple values
我有一个 cdef
函数 returning 一个 (int, int)
元组。我需要传播异常,因此必须为异常指定 return 类型。由于我的函数从不 returns 负值,这可能例如是 (-1, -1)
。使用 documentation 中指定的标准语法,我的函数将类似于
cdef (int, int) myFunction(int arg) except (-1, -1):
...
然而,当对上述函数进行cythonizing时,我得到了错误
Not allowed in a constant expression
我知道我可以在每次函数调用后通过
打开查找异常
cdef (int, int) myFunction(int arg) except *:
...
但这对我来说似乎效率低下。
如何传播具有多个 return 值的函数的异常?
答案是:你不能,至少不能使用当前版本的 Cython 的 cdef-tuples。
潜在的问题是,对于这样的元组,运算符 ==
未由 Cython 定义(这显然可以通过比较每个条目来完成 - 但在当前版本中未定义)。
对于一个简单的 cdef int myfun() except *
实际上并没有那么大的性能影响:
- 如果结果不是
-1
,则几乎没有开销(仅与 -1
比较)。
- 如果结果是
-1
,PyErr_Occurred
用于检查错误,这可能意味着相当大的开销(以上都是 nogil-blocks)
- 可以通过
except? X
选择临界值 X
,从而 minimize/optimize 必要的 PyErr_Occured
调用次数。
然而,如果 Cython 不知道一个类型的 ==
运算符(就像 Cython 的 c 元组一样),我们基本上处于 cdef void myfun() except *
的情况,这意味着没有捷径并且PyErr_Occured
必须总是 checked/called.
您可能会说 ==
是为 Cython 的元组定义的,因为它是经过编译的。但是如果你查看生成的代码,你会发现,为了比较,Cython 的元组被转换为 Python-元组。
我个人会首先选择 except *
,看看它是否真的具有可衡量的影响。因为 cdef
-function 显然可以有 Python-interaction,所以增加一点可能根本没有坏处。
如果是,最好的办法可能是更改函数的签名,例如
cdef int myFunction(int arg, (int, int) *a) except -1:
...
return 0
即使这感觉不太流畅 - 由于性能更好,可能值得麻烦。
我有一个 cdef
函数 returning 一个 (int, int)
元组。我需要传播异常,因此必须为异常指定 return 类型。由于我的函数从不 returns 负值,这可能例如是 (-1, -1)
。使用 documentation 中指定的标准语法,我的函数将类似于
cdef (int, int) myFunction(int arg) except (-1, -1):
...
然而,当对上述函数进行cythonizing时,我得到了错误
Not allowed in a constant expression
我知道我可以在每次函数调用后通过
打开查找异常cdef (int, int) myFunction(int arg) except *:
...
但这对我来说似乎效率低下。
如何传播具有多个 return 值的函数的异常?
答案是:你不能,至少不能使用当前版本的 Cython 的 cdef-tuples。
潜在的问题是,对于这样的元组,运算符 ==
未由 Cython 定义(这显然可以通过比较每个条目来完成 - 但在当前版本中未定义)。
对于一个简单的 cdef int myfun() except *
实际上并没有那么大的性能影响:
- 如果结果不是
-1
,则几乎没有开销(仅与-1
比较)。 - 如果结果是
-1
,PyErr_Occurred
用于检查错误,这可能意味着相当大的开销(以上都是 nogil-blocks) - 可以通过
except? X
选择临界值X
,从而 minimize/optimize 必要的PyErr_Occured
调用次数。
然而,如果 Cython 不知道一个类型的 ==
运算符(就像 Cython 的 c 元组一样),我们基本上处于 cdef void myfun() except *
的情况,这意味着没有捷径并且PyErr_Occured
必须总是 checked/called.
您可能会说 ==
是为 Cython 的元组定义的,因为它是经过编译的。但是如果你查看生成的代码,你会发现,为了比较,Cython 的元组被转换为 Python-元组。
我个人会首先选择 except *
,看看它是否真的具有可衡量的影响。因为 cdef
-function 显然可以有 Python-interaction,所以增加一点可能根本没有坏处。
如果是,最好的办法可能是更改函数的签名,例如
cdef int myFunction(int arg, (int, int) *a) except -1:
...
return 0
即使这感觉不太流畅 - 由于性能更好,可能值得麻烦。