简体   繁体   English

Python从分发在不同目录中的包访问模块

[英]Python accessing modules from package that is distributed over different directories

I have a question regarding one single module that is distributed over multiple directories. 我有一个关于分布在多个目录上的单个模块的问题。

Let's say I have these two file and directories: 假设我有这两个文件和目录:

~/lib/python
   xxx
      __init__.py
      util
         __init__.py
         module1.py
         module2.py
~/graphics/python
   xxx
      __init__.py
      misc
         __init__.py
         module3.py
         module4.py

So then in my Python modules, I did this: 那么在我的Python模块中,我这样做了:

import sys
pythonlibpath = '~/lib/python'
if pythonlibpath not in sys.path: sys.path.append(pythonlibpath)
import xxx.util.module1

which works. 哪个有效。

Now, the problem is that I need xxx.misc.module3, so I did this: 现在,问题是我需要xxx.misc.module3,所以我这样做了:

import sys
graphicslibpath = '~/graphics/python'
if graphicslibpath not in sys.path: sys.path.append(graphicslibpath)
import xxx.misc.module3

but I get this error: 但我得到这个错误:

ImportError: No module named misc.module3

It seems like it somehow still remembers that there was a xxx package in ~/lib/python and then tries to find misc.module3 from there. 似乎它仍然记得在〜/ lib / python中有一个xxx包然后尝试从那里找到misc.module3。

How do I get around this issue? 我该如何解决这个问题?

You can't without an extreme amount of trickery that pulls one package structure into the other. 你不能没有极端的诡计将一个包结构拉到另一个包结构中。 Python requires that all modules in a package be under a single subdirectory. Python要求包中的所有模块都在一个子目录下。 See the os source to learn how it handles os.path . 请参阅os源以了解它如何处理os.path

This is addressed by Implicit Namespace Packages in Python 3.3. Python 3.3中的隐式命名空间包解决了这个问题。 See PEP-420 . PEP-420

Python does indeed remember that there was a xxx package. Python确实记得有一个xxx包。 This is pretty much necessary to achieve acceptable performance, once modules and packages are loaded they are cached. 这对于实现可接受的性能非常必要,一旦加载了模块和包,它们就会被缓存。 You can see which modules are loaded by looking the the dictionary sys.modules . 您可以通过查看字典sys.modules来查看加载了哪些模块。

sys.modules is a normal dictionary so you can remove a package from it to force it to be reloaded like below: sys.modules是一个普通的字典,所以你可以从中删除一个包来强制它重新加载,如下所示:

import sys
print sys.modules
import xml
print sys.modules
del sys.modules['xml']
print sys.modules

Notice that after importing the xml package it is the dictionary, however it is possible to remove it from that dictionary too. 请注意,在导入xml包之后它是字典,但是也可以从该字典中删除它。 This is a point I make for pedagogical purposes only, I would not recommend this approach in a real application . 这是我仅用于教学目的的一点, 我不建议在实际应用中使用这种方法 Also if you need to use your misc and util packages together this would not work so great. 此外,如果您需要将miscutil软件包一起使用,这将无法实现。 If at all possible rearrange your source code structure to better fit the normal Python module loading mechanism. 如果可能的话,重新安排你的源代码结构,以更好地适应普通的Python模块加载机制。

This is an adaptation of an answer to a similar question . 这是对类似问题回答的改编。

Following up on @Gary's answer, the PEP 420 page says to use the following code on shared __init__.py packages. 按照@ Gary的回答, PEP 420页面说在共享的__init__.py包上使用以下代码。

__init__.py : __init__.py

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

This code should be placed inside the xxx directory's __init__.py . 此代码应放在xxx目录的__init__.py See the *s below 见下面的* 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

Some setup.sh file to add to the Python Path: 一些要添加到Python路径的setup.sh文件:

libPath=someroot/lib/python/
graphicsPath=someroot/graphics/python/
export PYTHONPATH=$PYTHONPATH:$libPath:$graphicsPath

Python test code (tested on Python versions 2.7.14 and 3.6.4 using pyenv ): Python测试代码(使用pyenv在Python版本2.7.14和3.6.4上测试 ):

import xxx.util.module1
import xxx.misc.module3 # No errors

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM