gpt4 book ai didi

如果放入命名空间包中,则子模块的python导入路径

转载 作者:行者123 更新时间:2023-12-03 16:10:29 27 4
gpt4 key购买 nike

我有一个用 C 编写的 python 模块,它有一个主模块和一个子模块(带点的名称,不确定这可以称为真正的子模块):

PyMODINIT_FUNC initsysipc(void) {
PyObject *module = Py_InitModule3("sysipc", ...);
...
init_sysipc_light();
}

static PyTypeObject FooType = { ... };
PyMODINIT_FUNC init_sysipc_light(void) {
PyObject *module = Py_InitModule3("sysipc.light", ...);
...
PyType_Ready(&FooType);
PyModule_AddObject(module, "FooType", &FooType);
}
该模块编译为 sysipc.so ,当我把它放在当前目录中时,下面的导入工作没有问题:
import sysipc
import sysipc.light
from sysipc.light import FooType
问题是我想把这个模块放在一个命名空间包中,文件夹结构是这样的:
company/
company/__init__.py
company/dept/
company/dept/__init__.py
company/dept/sys/
company/dept/sys/__init__.py
company/dept/sys/sysipc.so
所有三个 __init__.py仅包含标准 setuptool进口线:
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
在当前目录中,以下导入不起作用:
from company.dept.sys import sysipc;
from company.dept.sys.sysipc.light import FooType;
我应该如何导入模块 sysipc.light 中定义的类型和方法在这种情况下?
====================================
更新实际错误:
我有 sysipc.so构建,如果我在当前目录中运行 python 作为这个模块,导入将按预期工作:
[root@08649fea17ef 2]# python2
Python 2.7.18 (default, Jul 20 2020, 00:00:00)
[GCC 10.1.1 20200507 (Red Hat 10.1.1-1)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sysipc
>>> import sysipc.light
>>>
但是,如果我将其放入命名空间文件夹中,如下所示:
company/
company/__init__.py
company/dept
company/dept/__init__.py
company/dept/sys
company/dept/sys/sysipc.so
company/dept/sys/__init__.py
导入子模块将不起作用:
>>> from company.dept.sys import sysipc
>>> from company.dept.sys import sysipc.light
File "<stdin>", line 1
from company.dept.sys import sysipc.light
^
SyntaxError: invalid syntax
>>> from company.dept.sys.sysipc import light
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name light
>>>
该模块是用 this simple code 构建的,它适用于python2。我也有 same example for python3 .

最佳答案

引自 https://www.python.org/dev/peps/pep-0489/#multiple-modules-in-one-library :

To support multiple Python modules in one shared library, the library can export additional PyInit* symbols besides the one that corresponds to the library's filename.

Note that this mechanism can currently only be used to load extra modules, but not to find them. (This is a limitation of the loader mechanism, which this PEP does not try to modify.) ...


换句话说,您需要为 importlib 重组项目如下能够找到子模块 lightsysipc包裹:
company/__init__.py
company/dept/__init__.py
company/dept/sys/__init__.py
company/dept/sys/sysipc/__init__.py
company/dept/sys/sysipc/sysipc.so
company/dept/sys/sysipc/light.so -> sysipc.so # hardlink
light.so 之间的硬链接(hard link)和 sysipc.so可以通过以下方式创建:
ln company/dept/sys/sysipc/sysipc.so company/dept/sys/sysipc/light.so
然后在 company/dept/sys/sysipc/__init__.py您从 sysipc.so 导入所有符号使用:
from .sysipc import *
此外,您需要将子模块 C 扩展初始化函数的名称从 init_sysipc_light 更改为至 init_light对于 Python2,或来自 PyInit_sysipc_lightPyInit_light对于 Python3,因为 importlib通过查找导出的 PyInit_<module name> 来加载模块来自动态模块,这里的模块名只有 light ,即父包前缀不是(子)模块名称的一部分。
这是扩展代码(Python3)和几个测试函数:
#include <Python.h>

PyObject *sysipc_light_foo(PyObject *self, PyObject *args) {
printf("[*] sysipc.light.foo\n");
return PyLong_FromLong(0);
}

static PyMethodDef sysipc_light_methods[] = {
{"foo", (PyCFunction)sysipc_light_foo, METH_VARARGS, "sysipc.light.foo function"},
{NULL, NULL, 0, NULL}
};

static struct PyModuleDef sysipc_light_module = {
PyModuleDef_HEAD_INIT,
"sysipc.light",
"sysipc child module",
-1,
sysipc_light_methods
};

PyMODINIT_FUNC PyInit_light(void)
{
PyObject *module = NULL;

module = PyModule_Create(&sysipc_light_module);

return module;
}

PyObject *sysipc_bar(PyObject *self, PyObject *args) {
printf("[*] sysipc.bar\n");
return PyLong_FromLong(0);
}

static PyMethodDef sysipc_methods[] = {
{"bar", (PyCFunction)sysipc_bar, METH_VARARGS, "sysipc.bar function"},
{NULL, NULL, 0, NULL}
};

static struct PyModuleDef sysipc_module = {
PyModuleDef_HEAD_INIT,
"sysipc",
"sysipc parent module",
-1,
sysipc_methods
};

PyMODINIT_FUNC PyInit_sysipc(void)
{
PyObject *module = NULL;

module = PyModule_Create(&sysipc_module);

PyInit_light();

return module;
}
测试.py:
#!/usr/bin/env python3

from company.dept.sys import sysipc
from company.dept.sys.sysipc import light

sysipc.bar()
light.foo()
输出:
[*] sysipc.bar
[*] sysipc.light.foo

关于如果放入命名空间包中,则子模块的python导入路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63978903/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com