Cython语法声明有别名的类层次结构

8 投票
1 回答
1098 浏览
提问于 2025-04-18 05:00

这里有一个抽象的基类和一个具体的子类,我想通过Cython让它们在Python中可用:

class NodeDistance {

protected:
    const Graph& G;

public:
    NodeDistance(const Graph& G);
    virtual ~NodeDistance();
    virtual void preprocess() = 0;
    virtual double distance(node u, node v) = 0;
};


class NeighborhoodDistance: public NetworKit::NodeDistance {

public:
    NeighborhoodDistance(const Graph& G);
    virtual ~NeighborhoodDistance();
    virtual void preprocess();
    virtual double distance(node u, node v);
};

这是我第一次尝试为Cython声明这些类的接口。为了避免cppclass和Python包装类之间的命名冲突,我把每个Class都命名为_Class,后面跟上它的正确名称"Namespace::Class"

cdef extern from "../cpp/distmeasures/NodeDistance.h":
    cdef cppclass _NodeDistance "NetworKit::NodeDistance":
        _NodeDistance(_Graph G) except +
        void preprocess() except +
        double distance(node, node) except +


cdef extern from "../cpp/distmeasures/NeighborhoodDistance.h":
    cdef cppclass _NeighborhoodDistance(_NodeDistance) "NetworKit::NeighborhoodDistance":
        _NeighborhoodDistance(_Graph G) except +
        void preprocess() except +
        double distance(node, node) except +

但是现在,当我尝试表示_NeighborhoodDistance_NodeDistance的子类时,出现了语法错误。我哪里出错了呢?

Error compiling Cython file:
------------------------------------------------------------
...
        void preprocess() except +
        double distance(node, node) except +


cdef extern from "../cpp/distmeasures/NeighborhoodDistance.h":
    cdef cppclass _NeighborhoodDistance(_NodeDistance) "NetworKit::NeighborhoodDistance":
                                                   ^
------------------------------------------------------------

_NetworKit.pyx:1698:52: Syntax error in C++ class definition

1 个回答

2

我觉得在Cython 0.20.1中,你甚至无法同时表达基类和重命名的组合。你可以选择不重命名类,然后在cdef extern from中指定命名空间:

# C++ classes shown at the end
cdef extern from "example.hpp" namespace "example":
    cdef cppclass Base:
        void some_method() except +

    cdef cppclass Derived(Base):
        void some_method() except +

...或者不指定继承关系:

cdef extern from "example.hpp" namespace "example":
    cdef cppclass Base "example::Base":
        void some_method() except +

    cdef cppclass Derived "example::Derived":
        void some_method() except +

无论哪种方式,Cython似乎都不完全理解C++的继承关系,所以你需要进行显式转换:

def test():
    cdef Derived d
    cdef Base *p = <Base *>&d
    p.some_method()

这样做有点麻烦,因为这个转换实际上会关闭C++中的类型检查,但只要小心使用,还是可以安全的。(还有其他情况下,Cython的类型检查需要的转换在C/C++中其实是不必要的,这真让人遗憾。)

作为参考,这里是我使用的类:

// example.hpp
#include <cstdio>

namespace example {
    struct Base {
        virtual void some_method() = 0;
        virtual ~Base() = 0;
    };

    struct Derived {
        virtual void some_method()
        {
            std::puts("Hello!");
        }
        ~Derived()
        {
        }
    };
}

撰写回答