python 3.x C 扩展模块和子模块

python 3.x C extension module and submodule

当一个模块有子模块时,如何为 python 3.x 做一个 C 扩展?例如,我有一个名为 pet.c:

的文件
#include <Python.h>

PyObject* CatMeow(PyObject* self) {
    return PyUnicode_FromString( ">*<" );
}

static PyMethodDef CatFunctions[] = {
    {(char*) "meow", (PyCFunction) CatMeow, METH_NOARGS, NULL},
    {NULL, NULL, 0, NULL}
};

static PyModuleDef CatDef = {
    PyModuleDef_HEAD_INIT, "cat", "cat ext", -1, CatFunctions,
    NULL, NULL, NULL, NULL
};

PyMODINIT_FUNC PyInit_cat(void) {
    return PyModule_Create(&CatDef);
}

static PyModuleDef PetDef = {
    PyModuleDef_HEAD_INIT, "pet", "pet ext", -1, NULL,
    NULL, NULL, NULL, NULL
};

PyMODINIT_FUNC PyInit_pet(void) {
    PyObject* p = PyModule_Create(&PetDef);
    PyObject* c = PyInit_cat();
    Py_INCREF(c);
    PyModule_AddObject( p, "cat", c );
    return p;
}

当我使用以下 setup.py 构建它时:

from distutils.core import setup, Extension

setup( 
    name='pet', 
    version='0.0', 
    ext_modules=[Extension('pet', ['pet.c'])]
)

我能看到

>>> import pet
>>> pet.cat.meow()
'>*<'

>>> from pet import cat
>>> cat.meow()
'>*<'

这是预期的,但当我尝试时

>>> from pet.cat import meow

我有一个 ModuleNotFoundError 说...没有名为 'pet.cat' 的模块; 'pet' 不是包,如果我尝试

>>> from pet import cat
>>> from cat import meow

我有一个 ModuleNotFoundError 说...没有名为 'cat' 的模块。但是如果我检查 cat

的类型
>>> type(cat)
<class 'module'>

表示它是一个模块。

如何进行这项工作?将模块对象添加到另一个模块中,在 python 2.7 中使用效果很好。由于绝对导入样式,它不应该在 python3 中工作吗?或者我是否必须按照 PEP 489 中的描述进行多阶段初始化?

关于第一个抱怨宠物不是包裹的错误。如果 pet 只是为 cat 提供一个 parent,有一个简单的方法可以将它变成一个包:从 pet.c 中删除所有与 pet 相关的代码,并在 [=] 中使用 ext_package 23=]

from distutils.core import setup, Extension

setup( 
    name = 'pet',
    version = '0.0',
    ext_package = 'pet',
    ext_modules = [Extension('cat', ['pet.c'])]
)

运行 以上将创建一个名为'pet' 的目录和一个名称以'cat' 开头的共享库。这有效地创建了一个命名空间包——有两种类型的包,常规和命名空间,后者是不需要 __init__.py 的包(有关详细信息,请参阅 PEP 420)。从宠物之外,你可以做

>>> from pet import cat
>>> from pet.cat import meow 
>>> meow()
'>*<'
>>> cat.meow()
'>*<'

你不能 from cat import meow 的原因是因为模块的完全限定名称是 'pet.cat' 而不是 'cat',你可以从 cat.__name__ 中确认。如果你是运行目录pet里面的解释器,那你可以from cat import meow.