考虑以下项目结构:
a.py
test/
test_a.py
使用test_a.py
导入模块a
:
import a
正如预期的那样,在nosetests
目录中运行test
会导致导入错误:
ERROR: Failure: ImportError (No module named a)
但是,我注意到在__init__.py
目录中添加一个空test
文件会导致导入与nosetests
一起使用(但在使用Python运行test_a.py
时则不行)。你能解释一下原因吗?
我了解添加__init__.py
会使test
成为一个包。但这是否意味着import包含查找中包含包的目录?
答案 0 :(得分:5)
目录中存在__init__.py
文件会将test
从普通旧目录转换为python package。这会对sys.path
产生影响。
像这样修改test_a.py
模块:
import sys
def test_thing():
for i, p in enumerate(sys.path):
print i, p
try:
import a
except ImportError:
print('caught import error')
然后尝试从测试目录运行nosetests -s
,其中包含__init__.py
和不包含sys.path
。
注意:它是测试运行者,python test_a.py
。这在the second "Note" of this section here中有记录(感谢@davidism)。只要在包含和不包含包结构的情况下运行\(([^)]*?)\)
,您就不会看到任何变化。
答案 1 :(得分:2)
我查看了鼻子模块的源代码,这就是原因。
def importFromPath(self, path, fqname):
"""Import a dotted-name package whose tail is at path. In other words,
given foo.bar and path/to/foo/bar.py, import foo from path/to/foo then
bar from path/to/foo/bar, returning bar.
"""
# find the base dir of the package
path_parts = os.path.normpath(os.path.abspath(path)).split(os.sep)
name_parts = fqname.split('.')
if path_parts[-1] == '__init__.py':
path_parts.pop()
path_parts = path_parts[:-(len(name_parts))]
dir_path = os.sep.join(path_parts)
# then import fqname starting from that dir
return self.importFromDir(dir_path, fqname)
def importFromDir(self, dir, fqname):
"""Import a module *only* from path, ignoring sys.path and
reloading if the version in sys.modules is not the one we want.
"""
dir = os.path.normpath(os.path.abspath(dir))
在您从importFromPath调用importFromDir的情况下,' dir'是__init__.py
目录中上面的目录。因此,为您的测试添加__init__.py
的原因是“导入”'工作