Python动态加载模块/包冲突

时间:2015-07-24 10:47:58

标签: python python-2.7

我想使用imp.load_source动态加载源代码中的python(2.7而非3.x)模块,如果我没有将源代码路径附加到sys.path,则本地导入无法正常工作。在这种情况下,如何通过本地导入解决冲突模块名称?

我已经搜索了一段时间,无法找到解决方案。有任何想法吗?谢谢!

我喜欢的文件结构:

/tmp
|---runner
|   |-runner.py

/tmp/modules
|---bundle1
|   |--bundle
|   | |-__init__.py
|   | |-index.py
|   |-main.py
|
|---bundle2
    |--bundle
    | |-__init__.py
    | |-index.py
    |-main.py

runner.py

import os
import imp
import sys

sys.path.append("/tmp/modules/bundle1")
module_a = imp.load_source("Bundle1", "/tmp/modules/bundle1/main.py")
sys.path.append("/tmp/modules/bundle2")
module_b = imp.load_source("Bundle2", "/tmp/modules/bundle2/main.py")

module_a.start()
module_b.start()

bundle1 / main.py

from bundle import index
def start():
    index.a_func()

if __name__ == "__main__":
    start()

bundle2 / main.py

from bundle import index
def start():
    index.b_func()

if __name__ == "__main__":
    start()

因为from bundle

中无法找到b_func()bundle2/main.py的冲突

1 个答案:

答案 0 :(得分:0)

这里发生的事情是进口混乱。 Python正在缓存这样一个事实:它知道一个名为bundle的模块以及一个名为bundle.index的模块。 This post should help you understand imports a little more.如果你在你的负载之间打印sys.modules['bundle'],那就不那么神秘了。

print sys.modules.get('bundle', None)
# => yields None

sys.path.append("/tmp/modules/bundle1")
module_a = imp.load_source("Bundle1", "/tmp/modules/bundle1/main.py")
print sys.modules.get('bundle', None)
# => <module 'bundle' from '/tmp/modules/bundle1/bundle/__init__.pyc>

sys.path.append("/tmp/modules/bundle2")
module_b = imp.load_source("Bundle2", "/tmp/modules/bundle2/main.py")
print sys.modules.get('bundle', None)
# => <module 'bundle' from '/tmp/modules/bundle1/bundle/__init__.pyc>

如果您确实需要在一个命名空间中两次加载完全相同的模块名称,则需要在sys.modules之间删除其中的条目。此外,由于您只是追加到您的路径,因此当您加载module_b时,python会在找到/tmp/modules/bundle1/bundle/之前找到/tmp/modules/bundle2/bundle所以,要彻底解决您的问题。问题,您必须先添加信息或将其从sys.path 中删除。但一般来说,这实际上并不是很好的做法,当然如果您对模块名称有任何控制权,你应该改变它们。

print sys.modules.get('bundle', None)
# => yields None

sys.path.append("/tmp/modules/bundle1")
module_a = imp.load_source("Bundle1", "/tmp/modules/bundle1/main.py")
print sys.modules.get('bundle', None)
# => <module 'bundle' from '/tmp/modules/bundle1/bundle/__init__.pyc>

module_a.start()

# Delete python's knowledge of bundle1
del sys.modules['bundle']
del sys.modules['bundle.index']
sys.path.pop(sys.path.index('/tmp/modules/bundle1')

sys.path.append("/tmp/modules/bundle2")
module_b = imp.load_source("Bundle2", "/tmp/modules/bundle2/main.py")
print sys.modules.get('bundle', None)
# => <module 'bundle' from '/tmp/modules/bundle2/bundle/__init__.pyc>

module_b.start()

请注意,由于您删除了python对bundle1的了解,因此在moudle_a.start()之后尝试del会导致AttributeError

希望这有帮助。