为什么导入带点模块名时会因当前目录中的模块匹配高层级而失败?
我在尝试使用Python的一个标准库模块,咱们就叫它 foo.bar.baz
。
于是我写了一个小脚本,开头是
import foo.bar.baz
然后把它保存为 foo.py
。
当我运行这个脚本时,出现了一个导入错误(ImportError)。我花了一段时间才搞明白(我还在学习Python),最终意识到问题出在我给脚本起的名字上。一旦我把 foo.py
改成其他名字,问题就解决了。
所以我明白了,import foo
这个语句会先找 foo.py
这个脚本,然后才会去找标准库里的 foo
。但我不太明白,当我说 import foo.bar.baz
时,它到底在找什么?有没有可能 foo.py
里面的内容能让这个语句成立?如果没有,为什么Python解释器不继续去找像 foo/bar
这样的目录结构,并且里面有合适的 __init__.py
文件呢?
1 个回答
像 import foo.bar.baz
这样的导入语句,首先会导入 foo
,然后再从 foo
中获取 bar
,接着再从 foo.bar
中获取 baz
。至于 foo
在被导入后,是否能满足对 bar
或 bar.baz
的请求,这对导入 foo
来说并不重要。它只是一个模块。实际上,只有一个 foo
模块。无论是 import foo
还是 import foo.bar.baz
,都会找到同一个模块——就像用其他方式导入 foo
模块一样。
实际上,有一种方法可以让 foo
成为一个单独的模块,而不是一个包,同时还能满足像 import foo.bar.baz
这样的语句:它可以把 "foo.bar"
和 "foo.bar.baz"
添加到 sys.modules
字典中。这正是 os
模块对 os.path
所做的:它会根据平台导入正确的 "path" 模块(比如 posixpath
、ntpath
、os2path
等),并把它赋值给 path
属性。然后,它会执行 sys.modules["os.path"] = path
,这样就可以通过 os.path
导入这个模块,所以像 import os.path
这样的语句就能正常工作。其实这样做并没有什么必要——因为 os.path
在不导入的情况下也可以使用——但这是可能的。