Python C扩展命名空间与常规子模块混合?

2 投票
1 回答
713 浏览
提问于 2025-04-17 17:35

这个问题和以下内容有点相似:

嵌套的Python C扩展/模块?

不过有一点不同。在这里,我不是想把两个C扩展混在一起,而是想把一个C扩展和一个普通的Python子模块结合起来。

有没有办法让一个C扩展在“module.so”和子模块中的符号之间共享模块命名空间呢?

我的模块结构看起来是这样的:

facs/
    facs/
      __init__.py
      setup.py
      facs.so
      [*.c files]
      utils/
        __init__.py
        galaxy.py

如果我把“utils”从结构中去掉,我可以导入facs并看到facs.so的方法:

>>> import facs
>>> dir(facs)
['__doc__', '__file__', '__name__', '__package__', 'build', 'query', 'remove']

但是当我把utils子模块放回去,尝试导入不同的部分时,一个命名空间似乎会遮盖另一个(utils遮盖了facs.so导出的符号):

>>> import facs
>>> dir(facs)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
>>> import facs.utils
>>> facs.utils.galaxy.rsync_genomes("phix")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'galaxy'
>>> from facs.utils import galaxy
>>> galaxy.rsync_genomes("phix")
'Hello world'

正如你所看到的,在执行dir(facs)后,buildqueryremove都消失了,galaxy也没有正确导入,除非我使用from facs.utils import galaxy,而不是直接通过facs.utils.galaxy.rsync_genomes()来访问。

总之,我希望使用这个模块来做:

>>> import facs
>>> dir(facs)
['__doc__', '__file__', '__name__', '__package__', 'build', 'query', 'remove'
, 'utils'] <--- (Directly accessible from "facs")
>>> facs.utils.galaxy.rsync_genomes("phix")
'Hello world'

这个(目前正在开发中的)代码在这里:

https://github.com/brainstorm/facs/tree/develop

如果有人想自己试试的话。我正在使用虚拟环境,$PYTHONPATH看起来也没问题:

/home/roman/.venvburrito/lib/python:
/home/roman/.virtualenvs/py27/lib/python2.7/site-packages

而且安装似乎也成功了:

cd ~/.virtualenvs/py27/lib/python2.7/site-packages/facs-2.0dev-py2.7.egg/
(py27)$ ls
EGG-INFO  facs.py  facs.pyc  facs.so  utils/

似乎没有__init__.py文件被复制到顶层目录,但在那里的存在与否并没有影响上面描述的导入行为。

有什么想法吗?提前谢谢!

1 个回答

0

要小心哦,确保你先导入的是.so文件,而不是facs包。你是在facs包的源代码目录下运行你的Python控制台吗?

试着走出这个包的目录,事情就会变得清楚了。

另外,接下来的导入并不意味着你facs目录下的所有模块都会被导入:

>> import facs
>> dir (facs)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']

你需要在每个__init__.py文件中设置你的导入。例如,如果你想在import facs时导出一些来自.so文件的符号,你应该在你的__init__.py文件中写入以下内容:

>> from _facs import function_name, function_name .....

然后,当你import facs时,它就会为你导入那些函数。

对你的子包utils也采用同样的方式。

我还建议把你的facs.so文件重命名为_facs.so,这样可以避免包名和模块名之间的冲突。

撰写回答