第三方模块中导入的模块名称冲突问题

3
假设 mine.py 想要导入 moduleA 和 moduleB,但是 moduleA 和 moduleB 每个都尝试导入名为“moduleC”的模块。这些是两个不同的模块,它们都恰好被命名为“moduleC”。当运行 mine.py 时,根据 sys.path 的设置,可能会得到正确的“moduleC”,而另一个则会出现意外,从而导致混乱。
如果 moduleA 和 moduleB 是由不同的作者编写的,且我们都不是其中之一,则最好不要修改这些模块。对于 mine.py 的作者是否有可用的解决方案,而不修改 moduleA 或 moduleB?
以下问题询问如何在您是 moduleA 或 moduleB 的作者时解决此问题。 当存在同名模块时,如何从内置库中导入 当存在同名本地模块时,如何在 Python 中访问标准库模块? 我的具体情况 我希望在Python调试器pdb下运行名为PyMOL的程序。不幸的是,PyMOL有一个名为“cmd.py”的文件,它会与pdb导入的通常的cmd发生冲突。
PyMOL安装的相关部分如下:
pymol/
    __init__.py
    cmd.py

PyMOL通过执行__init__.py来运行。然后,该文件将cmd作为from pymol import cmd导入。

根据BrenBarn的指示,我可以成功地使pdb暂时从sys.path的前面删除pymol目录,以便正确导入cmd。之后,当PyMOL尝试导入其cmd时,它会崩溃。不知何故,在PyMOL导入之前但在pdb导入之后,我需要从导入模块搜索中删除Python的cmd

最简示例

$ ls
pymol/
$ ls pymol/
__init__.py  cmd.py

init.py

# insert some code into __init__.py directly

import sys
pymol_path = sys.path[0]
sys.path[0] = ""
import pdb
sys.path[0] = pymol_path

from pymol import cmd

# test a sandwich of calls that require each "cmd" modules
pdb.set_trace()    
cmd.foo()    
pdb.set_trace()
cmd.foo()

print "done!"

# original PyMOL __init__.py code would follow

cmd.py

def foo():
    print("cmd.foo()")

试一试

$ PYTHONPATH= python ./pymol/__init__.py
> /Users/khouli/scr/pymol_scr/pymol/__init__.py(11)<module>()
-> cmd.foo()
(Pdb) continue
cmd.foo()
> /Users/khouli/scr/pymol_scr/pymol/__init__.py(13)<module>()
-> cmd.foo()
(Pdb) continue
cmd.foo()
done!

编辑:上述方法现在似乎可以工作,但正如BrenBarn的答案所述,原始问题要求留下所有第三方代码未修改的解决方案可能不存在。这是由于PyMOL中的怪癖导致的。


你是说moduleA、moduleB和moduleC都是独立安装的模块(也就是说,不是moduleA或moduleB试图从其子包中导入moduleC,或其他什么情况)? - BrenBarn
我认为“moduleC”是moduleA和moduleB的子包。您能解释一下这有什么区别吗? - Praxeolitic
@Praxeolithic:如果moduleC是两个的子包,那么它可能已经可以工作了,因为每个都会导入自己的子包。 - BrenBarn
@BrenBarn 详细信息和进展已添加。 - Praxeolitic
我认为问题不仅仅在于包结构,而是因为你正在将 __init__.py 作为脚本运行;这会将其目录放在 sys.path 的最前面。直接运行 __init__.py 真的是你应该做的吗?通常这不是一个好的实践。 - BrenBarn
显示剩余4条评论
1个回答

2
你的问题不仅仅在于导入,而是因为你正在将__init__.py作为脚本运行。当你运行一个脚本时,Python会将包含该脚本的目录添加到sys.path的前面,并且这会影响所有后续的导入。
如果你直接运行一个你不想修改的文件,就没有办法自定义任何东西。除非你先运行自己的代码来设置路径,否则你无法进行任何诡秘的sys.path操作。如果你导入文件而不是运行它,那么你就有可能使用自己的代码来调整路径。
我怀疑这个问题在某种程度上是特定于PyMOL的,不幸的是,PyMOL在这方面似乎设计得不太好。从这里查看源代码,我发现PyMOL的__init__.py包括了很多自定义代码,做一些奇怪的事情,比如import __main__并检查正在运行的版本是否具有各种属性。你可以尝试使用该文件中描述的“不支持/实验性”方法,这涉及导入PyMOL而不是运行它。我不知道PyMOL的使用情况,所以不知道这会怎么样。
建议联系PyMOL的作者,建议他们修复这个问题。

__init__.py的顶部放置代码是可以的。事实上,这正是我目前正在尝试的。如果在__init__.py的其余部分之前运行代码是一个选项,那么适当的偷偷摸摸的sys.path操作是什么? - Praxeolitic
我现在在 OP 中所拥有的似乎已经正确导入了,但正如你所解释的那样,需要有点混乱并对 init.py 进行手术。 - Praxeolitic
@Praxeolitic:是的,显然如此。此外,我真的无法说出它如何/是否与真正的__init__.py正在执行的所有其他疯狂的事情结合使用。 - BrenBarn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接