鉴于我有以下目录结构,.
是当前工作目录
.
\---foo
\---bar
\---__init__.py
\---baz.py
当我运行python -c "import foo.bar.baz"
时,我得到了
Traceback (most recent call last):
File "<string>", line 1
ImportError: No module named foo.bar.baz
如果我echo "" > foo/__init__.py
,则上述命令有效。
我做错了什么或者我误解了__init__.py
的观点?我认为这是为了阻止他们不应该存在的模块,例如一个名为string
的目录,但是如果在我的示例中用foo
替换string
,我似乎被迫创建了永远不会被使用的模块,这样我就可以引用一个文件更深层次的。
更新
我正在使用一个为我生成__init__.py
的构建系统,并且正在强制执行目录结构,虽然我可能会混淆层次结构,但我更愿意添加{{1}我自己。要稍微改变一下这个问题,为什么我需要在每个级别而不是在顶部的python包?您只能从python路径或python路径中的一系列包中导入模块吗?
答案 0 :(得分:7)
是的,如果您希望将目录视为模块,则需要此文件。
需要
__init__.py
个文件才能使Python将目录视为包含包;这样做是为了防止具有通用名称的目录(例如字符串)无意中隐藏稍后在模块搜索路径上发生的有效模块。在最简单的情况下,__init__.py
可以只是一个空文件,但它也可以执行包的初始化代码或设置__all__
变量,稍后将对此进行描述。
https://docs.python.org/3/tutorial/modules.html#packages
我尝试创建非空__init__.py
。您很有可能通过在第一级提供最有用的对象(类/函数)来记录模块,去除用户/开发人员的嵌套导入......实际上,尽可能简单地使用相反 - 让我们说 - java进口
问题更新后修改
默认导入器/查找器(检查sys.meta_path
)是:
第三个是__init__.py
事物(实际上也是FrozenImporter)。
PathFinder
在sys.path
(以及包中定义的__path__
)的路径中搜索模块。该模块可以是独立的python文件(如果它位于搜索路径的根目录中),也可以是__init__.py
的目录。
参考你的例子:
foo/
bar/
__init__.py
baz.py
如果您在_init__.py
中创建foo/
,foo.bar.baz
将可用(如您所说)。
如果您将foo/
添加到sys.path
或通过PYTHONPATH=foo/
传递,bar.baz
将可用(请注意,如果没有父模块foo)。
如果您编写自己的finder(和Loader),您可以加载任何您想要的文件,不管它在哪里。这给了你很大的力量。例如,查看stack-overflow-import
,根据SO的搜索结果公开代码。