Python导入优先级:包还是模块?

时间:2010-11-03 22:56:37

标签: python import packages

我不清楚如何正确地命名这个问题。

案例1

假设我有以下目录结构。

foo
|
+- bar/__init__.py
|
+- bar.py

如果我有

from foo import bar

我如何知道导入哪个栏(bar.pybar/__init__.py)?有没有简单的方法来自动检测这种情况?

案例2

foo
|
+- foo.py
|
+- other.py

如果other.py有行

import foo

我如何知道导入哪个foo(foo或foo.foo)?再一次,是否有任何简单的方法可以自动检测这种情况?

5 个答案:

答案 0 :(得分:7)

TLDR;如果包在同一目录中,则它优先于同名模块。

来自文档:

  

“导入名为spam的模块时,解释器在当前目录中搜索名为spam.py的文件,然后在环境变量PYTHONPATH指定的目录列表中搜索这与shell变量PATH的语法相同,即目录名列表。“

这有点误导,因为解释器还会查找名为spam的包(一个名为spam的目录,其中包含__init__.py文件)。由于目录条目在搜索之前已经排序,因此如果它们位于同一目录中,则包优先于具有相同名称的模块,因为spam位于spam.py之前。

请注意,“当前目录”是相对于主脚本路径(__name__ == '__main__' is True)的路径。因此,如果您/home/billg正在呼叫/foo/bar.py,则“当前目录”指的是/foo

答案 1 :(得分:6)

来自python shell的

from foo import bar

print bar.__file__

应告诉您哪个文件已导入

罗布

答案 2 :(得分:2)

包(具有__init__.py的目录)优先于模块。很难找到这个事实的文档,但是您可以在源代码中看到这一点:python 2.7python 3.6(感谢@qff查找)。

您还需要在foo目录中使用__init__.py才能使您的示例正常工作。

如果other.py位于foo/内,那么它将加载foo.py(而非目录foo/),因为它将首先查看当前目录(除非你已经玩PYTHONPATH或sys.path)。

答案 3 :(得分:0)

在第一种情况下,您尝试从文件'foo.py'

导入功能栏

在第二步中,您尝试导入文件'foo.py'

答案 4 :(得分:0)

我想补充已接受的答案。对于Python 3.3+,引入了名称空间包,并遵循PEP 420的导入顺序:

在导入过程中,导入机制将继续迭代父路径中的每个目录,就像在Python 3.2中一样。在为父路径中的每个目录寻找名为"foo"的模块或软件包时:

  • 如果找到<directory>/foo/__init__.py,则将导入常规包并返回。
  • 如果未找到,但是找到了<directory>/foo.{py,pyc,so,pyd},则会导入并返回一个模块。扩展的确切列表因平台以及是否指定-O标志而异。这里的列表是代表性的。
  • 如果没有找到,但找到<directory>/foo并是一个目录,则会记录下来,并继续扫描并从父路径中的下一个目录继续进行。
  • 否则,扫描将继续使用父路径中的下一个目录。

如果在不返回模块或程序包的情况下完成了扫描,并且记录了至少一个目录,则将创建一个名称空间程序包。