Python:如何选择同名模块导入
假设我在一个叫做 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的新特性”。