Python:如何选择同名模块导入

6 投票
5 回答
2849 浏览
提问于 2025-04-15 13:31

假设我在一个叫做 openid.py 的文件里,然后我执行了:

from openid.consumer.discover import discover, DiscoveryFailure

我已经在我的python路径上有了 openid 模块,但解释器似乎在尝试使用我的 openid.py 文件。我该如何获取库的版本呢?

(当然,除了明显的“重命名你的文件”这个答案之外,其他的建议会更好)。

5 个回答

2

我不想讨论重命名的问题,而是想告诉你怎么做你想做的事情(不管这对你来说是否“好”;-)。解决方案其实并不复杂...

只需要设置一下 __path__!来个简单的演示:

$ mkdir /tmp/modules /tmp/packages
$ mkdir /tmp/packages/openid
$ echo 'print "Package!"' > /tmp/packages/openid/__init__.py
$ gvim /tmp/modules/openid.py
$ PYTHONPATH='/tmp/modules:/tmp/packages' python -c'import openid'
Module!
Package!

这个例子展示了一个叫做 openid 的模块是如何成功导入一个同名的包的,尽管这个模块的路径在 sys.path 中排在前面,而且 sys.modules['openid'] 在那时已经被设置好了。所有的“秘密”都在 openid.py 的简单代码里...:

print "Module!"
__path__ = ['/tmp/packages']
import openid

当然,如果没有 __path__ 的设置,它只会输出 Module!

当然,这种方法也适用于导入包中的子模块。你可以这样做:

$ echo 'print "Submod!"' > /tmp/packages/openid/submod.py

然后把 openid.py 的最后一行改成

from openid import submod

你就会看到:

$ PYTHONPATH='/tmp/modules:/tmp/packages' python -c'import openid'
Module!
Package!
Submod!
$ 
3

重命名它。这就是命名空间的概念。你的 openid 可以是你顶层模块 project 的一个子模块。你的 email 会和顶层模块 email 在标准库中发生冲突。

因为你的 openid 不是通用的,它为你的项目提供了一个特殊的情况。

9

这就是为什么绝对导入被选为新的默认行为。不过在2.6版本中,它们还不是默认的(可能在2.7版本中会成为默认)。你现在可以通过从未来导入它们来获得这种行为:

from __future__ import absolute_import

你可以在Nick提到的PEP中找到更多信息,或者在这份文档中(我觉得更容易理解)了解更多内容:“Python 2.5的新特性”

撰写回答