可以使用两个同名的Python包吗?

可以使用两个同名的Python包吗?,python,import,packages,Python,Import,Packages,我有一个关于进口的问题。这个问题似乎有点做作,但它的目的是探讨对包中的所有导入使用绝对导入的局限性。高度不鼓励相对导入(编辑:并且声明永远不要使用它们) 假设您收到两个大型ish软件包,它们都具有相同的名称,并且都使用符合PEP8的绝对进口: /pkg1 mod1.py (contains an absolute import: 'import pkg1.mod2') mod2.py ... /pkg1 mod1.py (

我有一个关于进口的问题。这个问题似乎有点做作,但它的目的是探讨对包中的所有导入使用绝对导入的局限性。高度不鼓励相对导入(编辑:并且声明永远不要使用它们)

假设您收到两个大型ish软件包,它们都具有相同的名称,并且都使用符合PEP8的绝对进口:

/pkg1 mod1.py (contains an absolute import: 'import pkg1.mod2') mod2.py ... /pkg1 mod1.py (contains an absolute import: 'import pkg1.mod3') mod3.py ... /pkg1 mod1.py(包含绝对导入:“import pkg1.mod2”) mod2.py ... /pkg1 mod1.py(包含绝对导入:“import pkg1.mod3”) mod3.py ... 也就是说,您正在从事一个Python项目,您希望在该项目中同时使用这两个包。比如说,如果您想在一个项目中使用同一软件包的两个版本,可能会出现这种情况

有没有办法将这两个包合并到项目层次结构中,以便您可以在整个项目中自由使用这两个包中的模块


对于解决方案,可以使用导入别名和临时修改sys.path。但是更改任何一个包目录的内容都是不合适的。

实际上,您应该使用名称空间(包)来正确分隔您希望最终使用的模块。在上面的代码中

/pkg1
 mod1 - can just import mod2
 mod2.py
 __init__.py

/pkg2
 mod1 - can just import mod2
 mod2.py
 __init__.py
在其他地方,您应该根据需要执行导入pkg1.mod1或导入pkg2.mod1。

我的初始测试(在Python 2.6和3.1中)建议以下操作:

import sys, re

import foo as foo1
for k in sys.modules:
    if re.match(r'foo(\.|$)', k):
        newk = k.replace('foo', 'foo1', 1)
        sys.modules[newk] = sys.modules[k]
        # The following may or may not be a good idea
        #sys.modules[newk].__name__ = newk
        del sys.modules[k]

sys.path.insert(0, './python')
import foo as foo2
for k in sys.modules:
    if re.match(r'foo(\.|$)', k):
        newk = k.replace('foo', 'foo2', 1)
        sys.modules[newk] = sys.modules[k]
        # The following may or may not be a good idea
        #sys.modules[newk].__name__ = newk
        del sys.modules[k]
然而,我只是针对非常简单的软件包进行了测试,只是出于好奇才尝试。一个问题是它可能会中断
重新加载
。Python并不是真正设计用来处理具有相同顶级名称的多个包


在这一点上,我尝试性地说,在一般情况下是不可能的,尽管在某些有限的情况下是可能的,但它非常脆弱。

简短的回答是否定的,Python不接受两个同名的包。(有一些称为“名称空间包”的东西可以让单个包在多个目录上实现,但它们需要将涉及的包设置为相互协作)

PEP 8不鼓励显式相对导入的方式是其更值得怀疑的建议之一,正是因为它使得重命名包以避免命名冲突变得更加困难。如果这两个包使用相对导入,您可以重命名其中一个或将其嵌套在另一个包中,然后使用它

导入别名在这里对您没有帮助,因为重要的是在
sys.modules
中结束的名称,它使用导入时的模块名称,而不是在导入模块中绑定的名称


如果你想要真正的异国情调,你可以写你自己的进口商(见政治公众人物302和其他)。如果您决定这么做,您几乎可以做任何您想做的事情。

不,但是您可以使用关键字“as”并根据需要重命名包名。 例如:


可读性很重要,但不如正确性重要。最简单的方法是重命名其中一个包的基本名称。Python实际上不支持版本化的包。@Keith:有没有一种方法可以“重命名包的一个基本名称”,而不改变包目录本身?此外,软件包不一定是不同的版本。这只是一个例子。@Keith:是的,在setuptools.PEP8中的
pkg_资源
的帮助下,这是一个很好的起点,但不是最后一句话;毕竟,“愚蠢的一致性是小头脑的妖精”。只是“import mod2”是一种老式的模棱两可的相对重要性,应该极力避免。如果需要新的相对导入,请使用“from.import mod2”或使用绝对导入。它用于在自包含的包中导入。这有什么不明确之处?只有在重命名sys.modules中的任何内容之前导入所有子模块,并且代码不包含任何延迟导入(即从函数内部导入)时,这才有效<所有模块中的代码>\uuuuuu名称
以及任何
\uuuuuuu模块
属性都将是错误的。正如您上次的评论所指出的,Python并不是为支持这种场景而设置的。我几乎准备好说“在一般情况下不可能”,但还没有充分研究模块内部来确定。在回答这个StackOverflow问题时,在IRC上,的作者告诉我,他的包是为解决类似问题而编写的。谢谢。您的意思是代替?包名称不必是导入名称。一个例子是替换()的下降,在这种情况下会发生什么?这不是关于两个包。你的答案是关于两个同名的类。
from tableaudocumentapi import Workbook as table