将Python类转换为Cython

3
我有以下Python代码:

class DisjointSet:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0 for x in range(n)]

    def find(self, v):
        if v != self.parent[v]:
            self.parent[v] = self.find(self.parent[v])
        return self.parent[v]

其余的代码在“代码复杂度”方面类似,这里不再列出。

因此,我想将上述代码翻译成Cython代码(我了解一些C++,并且我成功地将所有代码翻译成了C++,但我想尝试一下Cython,并看看它与C++和Python相比如何)。我有以下代码:

disjointset.pyx:

# distutils: language=c++
from libcpp.vector cimport vector

cdef class DisjointSet:
    cpdef public vector[int] parent, rank

    def __init__(self, int n):
        for i in range(n):
            self.parent.push_back(i)
            self.rank.push_back(0)

    def find(self, int v):
        if v != self.parent[v]:
            self.parent[v] = self.find(self.parent[v])
        return self.parent[v]

setup.py:

from distutils.core import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("cPercolation.pyx", annotate=True)
)

我在Windows powershell中运行python setup.py build_ext --inplace来编译代码。但是,当我在Python中导入代码并尝试使用时,有时会出现错误(进程未返回0),有时调用find方法时会出现RecursionError。那么正确的翻译方式是什么?我已经阅读了官方文档,但对像cdefcpdef这样的内容仍不确定。
编辑:我添加了for循环以解决问题,但我应该如何改进cython代码?当我查看生成的html文件时,仍然有许多黄色高亮显示(Python交互)。具体而言,我想问如何使用cdefcpdef使类方法(DisjointSet.find)更像C++代码。

它是针对哪个输入崩溃的? - ead
你的Python和Cython代码做了不同的事情:在初始化之后,self.parent中只有一个元素而不是n个,这与Python版本不同。 - ead
我已经发现了我的错误并通过添加for循环进行了修复,但我仍然不知道如何优化我的代码,使其更像使用Cython的C ++。 - Physicist
1个回答

6

C++的vector运算符[]不会检查边界,越界访问会导致随机值,这将在后续向量访问中导致段错误,你会注意到一个非零退出码。

相反,使用.at()它有边界检查,cython将把std::out_of_range异常转换为IndexError

 def find(self, int v):
     try:
         pv = self.parent.at(v)
     except IndexError:
         return None
     ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接