编译不同包中依赖的pyx文件
我在不同的包中编译cdef类型时遇到了问题,但在Cython的文档中找不到解释。
我在我的Python源代码树的根目录下有一个setup.py文件:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = [
Extension("flink.pytk.defs.FragIdx",
sources = ["flink/pytk/defs/FragIdx.pyx"]),
Extension("flink.pytk.fragments.STK_idx",
sources = ["flink/pytk/fragments/STK_idx.pyx"])
]
)
FragIdx是一个cdef类型,定义在flink/pytk/defs/FragIdx.pyx文件中:
cdef class FragIdx:
cdef public FragIdx parent
cdef public FragIdx root
cdef public tuple label
...
而STK_idx是FragIdx的扩展,定义在flink/pytk/fragments/STK_idx.pyx文件中:
from flink.pytk.defs.FragIdx import FragIdx
cdef class STK_idx(FragIdx):
...
当我尝试使用开头提到的setup.py进行编译时,FragIdx编译得很好,但在编译STK_idx时却出现了以下错误信息:
flink/pytk/fragments/STK_idx.pyx:5:5: 'FragIdx' is not a type name
请注意,我的源代码树的根目录已经在$PYTHONPATH中列出。
如果有人能对此提供一些帮助,我将非常感激,谢谢!
Daniele
1 个回答
哦,对于那些遇到类似问题的人,我好像找到了答案。
我原本以为 Python 会自动扫描编译到共享库 FragIdx.so 中的符号,但看起来这些信息必须通过一个 .pxd 文件明确提供(这个文件在运行 Cython 后会变成 C 的头文件)。
这个过程基本上分为两个步骤:
- 为父类创建一个定义文件(
.pxd
); - 在子类模块中通过
cimport
导入父类定义(而不是用import
)。
为了更通俗易懂。
假设你在模块 pkg1.mod1
中定义了一个 cdef 类型 A
。然后你在 pkg2.mod2
中定义了一个继承自 A
的类型 B
。
你的目录结构大概是这样的:
pkg1/
mod1.pyx
mod1.pxd
pkg2/
mod2.pyx
mod2.pxd
在 pkg1/mod1.pxd
中,你可能会有:
cdef class A:
cdef int a
cdef int b
而在 pkg1/mod1.pyx
中,你会提供你类的方法。
在 pkg2/mod2.pxd
中,你会有:
from pkg1.mod1 cimport A #note "cimport"!!
cdef class B(A):
cdef ... # your attributes here
同样,在 pkg2/mod2.pyx
中,你需要再次 cimport
A 符号:
from pkg1.mod1 cimport A #note "cimport"!!
cdef class B(A):
... # your methods here
有趣的是,如果你只是想在 Python 代码中使用 A
,而不是用它来定义一个子类型,那么定义文件 mod1.pxd
就不需要了。这是因为在创建扩展类型时,你需要让 C 编译器能找到这些定义,而在运行 Python 代码时就没有这个问题。不过,由于这点不是很直观,可能需要特别说明一下。
这些信息其实在 Cython 文档 中可以找到,虽然可能可以更明确一些。
希望这些信息能对某些人有所帮助。