我对一个分布在多个目录中的单个模块有疑问。
假设我有这两个文件和目录:
~/lib/python
xxx
__init__.py
util
__init__.py
module1.py
module2.py
~/graphics/python
xxx
__init__.py
misc
__init__.py
module3.py
module4.py
然后在我的Python模块中,我做到了这一点:
import sys
pythonlibpath = '~/lib/python'
if pythonlibpath not in sys.path: sys.path.append(pythonlibpath)
import xxx.util.module1
有效。
现在,问题是我需要xxx.misc.module3,所以我这样做了:
import sys
graphicslibpath = '~/graphics/python'
if graphicslibpath not in sys.path: sys.path.append(graphicslibpath)
import xxx.misc.module3
但是我收到了这个错误:
ImportError: No module named misc.module3
似乎它仍然记得〜/ lib / python中有一个xxx包,然后尝试从那里找到misc.module3。
如何解决此问题?
答案 0 :(得分:2)
你不能没有极端的诡计将一个包结构拉到另一个包结构中。 Python要求包中的所有模块都在一个子目录下。请参阅os
来源,了解其处理方式os.path
。
答案 1 :(得分:1)
Python确实记得有一个xxx
包。这对于实现可接受的性能非常必要,一旦加载了模块和包,它们就会被缓存。您可以通过查看字典sys.modules
来查看加载了哪些模块。
sys.modules
是一个普通词典,因此您可以从中删除一个包以强制重新加载,如下所示:
import sys
print sys.modules
import xml
print sys.modules
del sys.modules['xml']
print sys.modules
请注意,导入xml
包后它是字典,但也可以从该字典中删除它。这是我仅用于教学目的的一点,我不建议在实际应用中使用这种方法。此外,如果您需要同时使用misc
和util
个软件包,这将无法实现。如果可能的话,重新安排你的源代码结构,以更好地适应普通的Python模块加载机制。
答案 2 :(得分:1)
Python 3.3中的隐式命名空间包解决了这个问题。请参阅PEP-420。
答案 3 :(得分:1)
这是answer to a similar question的改编。
关注@ Gary的回答,PEP 420 page表示要在共享的__init__.py
包中使用以下代码。
__init__.py
:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
此代码应放在xxx目录的__init__.py
内。
见下面的* s
someroot/
├── graphics
│ └── python
│ └── xxx
│ ├── ****__init__.py****
│ └── misc
│ ├── __init__.py
│ ├── module3.py
│ └── module4.py
└── lib
└── python
└── xxx
├── ****__init__.py****
└── util
├── __init__.py
├── module1.py
└── module2.py
要添加到Python路径的一些setup.sh
文件:
libPath=someroot/lib/python/
graphicsPath=someroot/graphics/python/
export PYTHONPATH=$PYTHONPATH:$libPath:$graphicsPath
Python测试代码(使用pyenv在Python版本2.7.14和3.6.4上测试):
import xxx.util.module1
import xxx.misc.module3 # No errors