[英]Python import precedence: packages or modules?
我不清楚如何正确命名这个问题。
案例一
假设我有以下目录结构。
foo
|
+- bar/__init__.py
|
+- bar.py
如果我有
from foo import bar
我如何知道正在导入哪个栏( bar.py
或bar/__init__.py
)? 有没有什么简单的方法可以自动检测到这种情况的发生?
案例二
foo
|
+- foo.py
|
+- other.py
如果 other.py 有这条线
import foo
我如何知道正在导入哪个 foo(foo 或 foo.foo)? 同样,是否有任何简单的方法可以自动检测到这种情况的发生?
TLDR; 如果包在同一目录中,则包优先于同名模块。
从文档:
“当导入名为
spam
的模块时,解释器spam.py
在当前目录中搜索名为spam.py
的文件,然后在环境变量PYTHONPATH
指定的目录列表中搜索。这与 shell 变量 PATH 具有相同的语法,即是,目录名称列表。”
这有点误导,因为解释器还会寻找一个名为spam
的包(一个名为spam
的目录,其中包含一个__init__.py
文件)。 由于目录条目在搜索之前被排序,如果包在同一个目录中,包优先于同名模块,因为spam
在spam.py
之前。
请注意,“当前目录”是相对于主脚本路径(其中__name__ == '__main__' is True
路径)。 因此,如果您在/home/billg
调用/foo/bar.py
,“当前目录”是指/foo
。
从 python 外壳:
from foo import bar
print bar.__file__
应该告诉你哪个文件被导入了
罗布
包(带有__init__.py
目录)优先于模块。 这个事实的文档很难找到,但你可以在源代码中看到这个: python 2.7 , python 3.6 (感谢@qff 的发现)。
您还需要 foo 目录中的__init__.py
才能让您的示例工作。
如果other.py
在foo/
内,那么它将加载foo.py
(不是目录foo/
),因为它会首先查看当前目录(除非您已经使用过 PYTHONPATH 或 sys.path)。
我想补充已接受的答案。 对于Python 3.3+
,引入了命名空间包,根据PEP 420的导入顺序如下:
在导入处理期间,导入机制将继续迭代父路径中的每个目录,就像在 Python 3.2 中一样。 在查找名为
"foo"
的模块或包时,对于父路径中的每个目录:
- 如果找到
<directory>/foo/__init__.py
,则导入并返回常规包。- 如果没有,但是
<directory>/foo.{py,pyc,so,pyd}
被找到,一个模块被导入并返回。 确切的扩展列表因平台以及是否指定了-O
标志而异。 这里的列表具有代表性。- 如果没有,但是
<directory>/foo
被找到并且是一个目录,它被记录下来并且扫描继续在父路径中的下一个目录。- 否则,扫描将继续使用父路径中的下一个目录。
如果扫描完成而没有返回模块或包,并且至少记录了一个目录,则创建一个命名空间包。
在第一种情况下,您尝试从文件“foo.py”导入功能栏
在第二个你试图导入文件 'foo.py'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.