'Exception ignored in:' cython 扩展 类 及其 `cdef` 方法
'Exception ignored in:' cython extension classes and their `cdef` methods
我有一些 cython classes,在他们的 cdef
方法中,我有 assert
语句。但是,例如,我没有得到我可以捕获的 AssertionError
,而是得到了 Exception ignored in:
但我无法捕获它(pytest
也将此报告为警告)
此外,不会引发和忽略其他发生的错误(assert
错误除外)。
作为一个简单的例子,假设我有一个名为 Node.pyx
的节点 class
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
或 simpel 安装脚本编译所有这些,所有编译都很好。然而,运行这个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
所以,这个问题还是比较容易解决的。应该从 cdef
函数中删除 void
以便它 return 正确的错误消息,而不是忽略错误。
原因是,当函数定义为 void
return 时,将创建、报告、销毁错误消息,并且函数将从异常点 return 和 return 语句永远不会被执行。
因此,只需从 remove_child
和 remove_parent
函数中删除 .pyx
和 .pxd
中的 void
即可使其按预期运行,并且错误信息可以正常咳嗽。
更多信息here
参见:
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 +:
描述了表格。
我有一些 cython classes,在他们的 cdef
方法中,我有 assert
语句。但是,例如,我没有得到我可以捕获的 AssertionError
,而是得到了 Exception ignored in:
但我无法捕获它(pytest
也将此报告为警告)
此外,不会引发和忽略其他发生的错误(assert
错误除外)。
作为一个简单的例子,假设我有一个名为 Node.pyx
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
或 simpel 安装脚本编译所有这些,所有编译都很好。然而,运行这个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
所以,这个问题还是比较容易解决的。应该从 cdef
函数中删除 void
以便它 return 正确的错误消息,而不是忽略错误。
原因是,当函数定义为 void
return 时,将创建、报告、销毁错误消息,并且函数将从异常点 return 和 return 语句永远不会被执行。
因此,只需从 remove_child
和 remove_parent
函数中删除 .pyx
和 .pxd
中的 void
即可使其按预期运行,并且错误信息可以正常咳嗽。
更多信息here
参见:
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 +:
描述了表格。