问题描述
我想通过在 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 提供的解决方案
import osmium
cdef class CounterHandlerBase:
cdef list nodes,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
import osmium
cdef class DummyBase:
def __init__(self):
pass
cdef class CounterHandler(DummyBase,osmium.SimpleHandler): # osmium.SimpleHandler
cdef list nodes,relations
def __init__(self):
DummyBase.__init__(self)
osmium.SimpleHandler.__init__(self)
self.nodes = []
self.ways = []
self.relations = []
cdef node(self,r):
pass
错误信息:
Traceback (most recent call last):
File "C:/Users/Administrator/DropBox (ASU)/Work/CAVLite/OSM2GMNS/V2/cython_test/tets.py",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'
解决方法
这里有很多选择:
-
你真的需要它成为
cdef class
吗?您对此是否有真正的原因(除了普遍的、未经测试的“cdef class
es 更快”的信念之外)?也许您可以改用常规课程?您不希望使用任何无法在 Python 中表示的属性(例如 C 指针)。请记住,Cython 仍然编译常规类的def
函数,因此可能没有您想象的速度差异。 -
将其拆分为需要是
cdef class
的位和不需要的位(这仅在与osmium.SimpleHandler
的交互位于不需要的位时才有效) :cdef class CounterHandlerBase: # code goes here class CounterHandler(CounterHandlerBase,osmium.SimpleHandler): # more code goes here
-
限制是 first 基数必须是
cdef class
(这实际上是 Python 内置的一个相当强的限制)。第二个/后续基础可以是常规类。因此,您可以创建一个“虚拟”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 中重新编写东西是否会加快速度。