通过在Cython中继承python类来构建扩展类

2024-10-02 18:25:08 发布

您现在位置:Python中文网/ 问答频道 /正文

我想通过继承Cython中的python类来构建一个子类。似乎我不能直接做,因为我在下面出错了。有什么解决办法吗

代码(osmium是第三方python包,可以使用pip安装):

import osmium

cdef class CounterHandler(osmium.SimpleHandler):
    cdef list nodes, ways, relations
    def __init__(self):
        osmium.SimpleHandler.__init__(self)
        self.nodes = []
        self.ways = []
        self.relations = []

    def node(self, n):
        pass

    def way(self, w):
        pass

    def relation(self, r):
        pass

错误消息:

add.pyx:22:32: First base of 'CounterHandler' is not an extension type
Traceback (most recent call last):
  File "setup.py", line 11, in <module>
    ext_modules=cythonize("add.pyx"))
  File "C:\ProgramData\Miniconda3\envs\osmium\lib\site-packages\Cython\Build\Dependencies.py", line 1102, in cythonize
    cythonize_one(*args)
  File "C:\ProgramData\Miniconda3\envs\osmium\lib\site-packages\Cython\Build\Dependencies.py", line 1225, in cythonize_one
    raise CompileError(None, pyx_file)
Cython.Compiler.Errors.CompileError: add.pyx

我尝试了DavidW提供的解决方案

解决方案2代码:

import osmium

cdef class CounterHandlerBase:
    cdef list nodes, ways, relations
    def __init__(self):
        self.nodes = []
        self.ways = []
        self.relations = []

    cdef node(self, n):
        pass

    cdef way(self, w):
        pass

    cdef relation(self, r):
        pass

class CounterHandler(CounterHandlerBase, osmium.SimpleHandler):    # osmium.SimpleHandler
    def __init__(self):
        CounterHandlerBase.__init__(self)
        osmium.SimpleHandler.__init__(self)

错误消息:

Traceback (most recent call last):
  File "C:/Users/Administrator/Dropbox (ASU)/Work/CAVLite/OSM2GMNS/V2/cython_test/tets.py", line 7, in <module>
    import solution2 as solution
  File "solution2.pyx", line 28, in init solution2
    class CounterHandler(CounterHandlerBase, osmium.SimpleHandler):    # osmium.SimpleHandler
TypeError: multiple bases have instance lay-out conflict

解决方案3 代码:

import osmium

cdef class DummyBase:
    def __init__(self):
        pass

cdef class CounterHandler(DummyBase, osmium.SimpleHandler):    # osmium.SimpleHandler
    cdef list nodes, ways, relations
    def __init__(self):
        DummyBase.__init__(self)
        osmium.SimpleHandler.__init__(self)
        self.nodes = []
        self.ways = []
        self.relations = []

    cdef node(self, n):
        pass

    cdef way(self, w):
        pass

    cdef relation(self, r):
        pass

错误消息:

Traceback (most recent call last):
  File "C:/Users/Administrator/Dropbox (ASU)/Work/CAVLite/OSM2GMNS/V2/cython_test/tets.py", line 7, in <module>
    import solution3 as solution
  File "solution3.pyx", line 16, in init solution3
    cdef class CounterHandler(DummyBase, osmium.SimpleHandler):    # osmium.SimpleHandler
TypeError: best base 'osmium._osmium.SimpleHandler' must be equal to first base 'solution3.DummyBase'

Tags: inselfinitdeflinepassclassfile
1条回答
网友
1楼 · 发布于 2024-10-02 18:25:08

这里有许多选项:

  1. 你真的需要它成为cdef class吗?你有没有真正的原因(除了一个普遍的、未经测试的信念,即“cdef classes更快”)之外?也许你可以用普通班代替?您看起来没有使用任何不能在Python中表示的属性(例如C指针)。请记住,Cython仍然编译常规类的def函数,因此可能没有您想象的速度差异

  2. 将其拆分为需要为cdef class的位和不需要的位(仅当与osmium.SimpleHandler的交互在不需要的位中时,这才有效):

    cdef class CounterHandlerBase:
        # code goes here
    
    class CounterHandler(CounterHandlerBase, osmium.SimpleHandler):
        # more code goes here
    
    
  3. 限制是第一个基必须是cdef class(这实际上是Python内置的一个相当强的限制)。第二个/后续的基可以是常规类。因此,您可以创建一个“dummy”cdef基类来填充该角色:

    cdef class DummyBase:
        pass
    
    cdef class CounterHandler(DummyBase, osmium.SimpleHandler):
        # code goes here...
    

编辑:根据您报告的错误,看起来osmium.SimpleHandler已经是用C/C++编写的扩展类型。不幸的是,这意味着它不可能在cdef class中继承,因为Python中内置了对对象布局的限制(可能将其定义为"external cdef class"可以工作,但它看起来是从by pybind11生成的,这使得开发底层结构非常困难)

因此,在这种情况下,选项2和3永远不会起作用。由于它是用C++编写的,我怀疑在Cython重写东西会加速一切。p>

相关问题 更多 >