【问题标题】:Cython exception propagation for cdef functions returning multiple values返回多个值的 cdef 函数的 Cython 异常传播
【发布时间】:2021-02-23 13:57:27
【问题描述】:

我有一个 cdef 函数返回一个 (int, int) 元组。我需要传播异常,因此必须指定异常的返回类型。由于我的函数从不返回负值,这可能是例如是(-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 *:
    ...

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

如何为具有多个返回值的函数传播异常?

【问题讨论】:

    标签: python exception cython cythonize


    【解决方案1】:

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

    根本问题是,对于此类元组,Cython 未定义运算符 ==(这显然可以通过比较每个条目来完成 - 但在当前版本中未定义)。

    对于一个简单的cdef int myfun() except * 而言,实际上并没有对性能造成很大影响:

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

    但是,如果 Cython 不知道某个类型的 ==-operator(与 Cython 的 c 元组一样),我们基本上处于 cdef void myfun() except * 的情况下,这意味着没有捷径并且必须始终使用 PyErr_Occured检查/调用。


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


    我个人会先选择except *,看看它是否真的有可衡量的影响。因为cdef-function 显然可以与 Python 交互,所以添加一点点可能根本不会受到伤害。

    如果是这样,最好的可能是更改函数的签名,例如

     cdef  int myFunction(int arg, (int, int) *a) except -1:
          ...
          return 0
    

    即使这感觉不那么顺利 - 由于性能更好,这可能是值得的。

    【讨论】:

    • 传递int 指针是个好主意!我认为这是一个完美的解决方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-22
    • 2012-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    相关资源
    最近更新 更多