我不清楚如何正确地命名这个问题。
案例1
假设我有以下目录结构。
foo
|
+- bar/__init__.py
|
+- bar.py
如果我有
from foo import bar
我如何知道导入哪个栏(bar.py
或bar/__init__.py
)?有没有简单的方法来自动检测这种情况?
案例2
foo
|
+- foo.py
|
+- other.py
如果other.py有行
import foo
我如何知道导入哪个foo(foo或foo.foo)?再一次,是否有任何简单的方法可以自动检测这种情况?
答案 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)
:
from foo import bar
print bar.__file__
应告诉您哪个文件已导入
罗布
答案 2 :(得分:2)
包(具有__init__.py
的目录)优先于模块。很难找到这个事实的文档,但是您可以在源代码中看到这一点:python 2.7,python 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
并是一个目录,则会记录下来,并继续扫描并从父路径中的下一个目录继续进行。- 否则,扫描将继续使用父路径中的下一个目录。
如果在不返回模块或程序包的情况下完成了扫描,并且记录了至少一个目录,则将创建一个名称空间程序包。