【问题标题】:'Exception ignored in:' cython extension classes and their `cdef` methods'例外被忽略:' cython 扩展类及其 `cdef` 方法
【发布时间】:2021-02-13 15:09:51
【问题描述】:

我有一些 cython 类,在他们的 cdef 方法中,我有 assert 语句。但是,例如,我没有得到可以捕获的AssertionError,而是得到了Exception ignored in:,但我无法捕获它(pytest 也将此报告为警告) 此外,不会引发和忽略其他发生的错误(assert 除外)。

举个简单的例子,假设我有一个名为 Node.pyx 的 Node 类

cdef class Node:
    def __init__(self, ident):
        self.identifier = ident
        self.children = set()
        self.parents = set()

    cdef void add_child(self, Node child):
        self.children.add(child.identifier)
        child.parents.add(self.identifier)

    cdef void add_parent(self, Node parent):
        self.parent.add(parent.identifier)
        parent.children.add(self.identifier)

    cdef void remove_child(self, Node child):
        assert child.identifier in self.children

        self.children.remove(child.identifier)
        child.parents.remove(self.identifier)

    cdef void remove_parent(self, Node parent):
        assert parent.identifier in self.parents

        self.parents.remove(parent.identifier)
        parent.children.remove(self.identifier)

及其对应的Node.pxd文件

cdef class Node:
    cdef int identifier
    cdef set children
    cdef set parents

    cdef void add_child(self, Node child)
    cdef void add_parent(self, Node parent)
    cdef void remove_child(self, Node child)
    cdef void remove_parent(self, Node parent)

由于这都是cdef,它只能被另一个pyx 脚本或函数使用。所以让我们用另一个脚本来测试节点,node_test.pyx

from Node cimport Node

def test_error_raising():
        cdef Node node1 = Node(1)
        cdef Node node2 = Node(2)

        node1.remove_parent(node2)

现在,如果我用cythonize -i *pyx 或简单的设置脚本编译所有这些,一切都编译得很好。但是,运行这个test_node.py

from node_test import test_error_raising

try:
    test_error_raising()
except AssertionError:
    print("You have assertion error!")

我明白了

AssertionError
Exception ignored in: 'Node.Node.remove_parent'
Traceback (most recent call last):
  File "test_node.py", line 5, in <module>
    test_error_raising()
AssertionError:

系统和版本:

Distributor ID: Ubuntu
Description:    Ubuntu 20.04.2 LTS

Cython version 0.29.21

Python 3.8.5

【问题讨论】:

    标签: python cython cythonize


    【解决方案1】:

    见:

    https://cython.readthedocs.io/en/latest/src/userguide/language_basics.html#error-return-values

    除了以上,有用的:

    cdef <some_type> some_func() except? -1:
    
    cdef <some_type> some_func() except *:
    
    cdef <some_type> some_func() except +:
    

    描述了表格。

    【讨论】:

      【解决方案2】:

      所以,这个问题很容易解决。应该从cdef 函数中删除void,以便它返回正确的错误消息,而不是忽略错误。 原因是当函数被定义为返回void时,错误信息会被创建、报告、销毁,函数会从异常点返回,return语句永远不会被执行。

      因此,只需从 .pyx.pxd 中的 remove_childremove_parent 函数中删除 void 即可使其行为符合预期,并且可以正常输出错误消息。

      更多信息here

      【讨论】:

      • 我认为cdef void func() except * 也可以。它告诉 Cython 该函数可以引发错误,并在调用该函数后始终检查 Python 错误状态。
      • 真的!我后来意识到了这一点。我只是决定发布问题并回答它,以防有人陷入与我相同的陷阱并且没有非常彻底地阅读 cython 文档并在以后感到困惑。
      猜你喜欢
      • 2021-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多