为什么我在每个级别都需要__init__.py?

qui*_*tle 12 python python-module python-import

鉴于我有以下目录结构.作为当前工作目录

.
\---foo
    \---bar
        \---__init__.py
        \---baz.py
Run Code Online (Sandbox Code Playgroud)

当我跑步时,python -c "import foo.bar.baz"我得到了

Traceback (most recent call last):
  File "<string>", line 1
ImportError: No module named foo.bar.baz
Run Code Online (Sandbox Code Playgroud)

如果我echo "" > foo/__init__.py,上面的命令有效.

我做错了什么或者我是否误解了这一点__init__.py?我认为这是停止现有的模块,他们不应该,其中例如一个名为string,但如果更换foostring在我的例子中,我似乎不得不创建一个不应该被使用的模块,只是让我可以引用文件更深层次的.

更新

我正在使用一个构建系统,它正在__init__.py为我生成并正在执行目录结构,虽然我可以搞乱层次结构,但我更愿意添加__init__.py自己.要稍微改变一下这个问题,为什么我需要在每个级别而不是在顶部的python包?只是一个规则,你只能从python路径或python路径的一系列包中导入模块?

kwa*_*nek 8

是的,如果您希望将目录视为模块,则需要此文件.

__init__.py需要这些文件使Python将目录视为包含包; 这样做是为了防止具有通用名称的目录(例如字符串)无意中隐藏稍后在模块搜索路径上发生的有效模块.在最简单的情况下,__init__.py可以只是一个空文件,但它也可以执行包的初始化代码或设置__all__变量,稍后描述.

https://docs.python.org/3/tutorial/modules.html#packages

我尝试创建非空__init__.py.您很有可能通过在第一级提供最有用的对象(类/函数)来记录模块,去除用户/开发人员的嵌套导入......实际上,尽可能简单地使用对比 - 让我们说 - java导入

问题更新后编辑

默认导入器/查找器(检查sys.meta_path)是:

  1. BuiltinImporter - 搜索/加载内置模块
  2. FrozenImporter - 搜索/加载冻结模块(例如*.pyc)
  3. PathFinder - 您感兴趣的那个,允许根据文件系统搜索/加载模块

第三个是__init__.py事物(实际上也是FrozenImporter).

所述PathFinder用于从路径搜索模块sys.path(以及__path__在包中定义的).该模块可以是独立的python文件(如果它位于搜索路径的根目录中),也可以是目录__init__.py.

参考你的例子:

foo/
  bar/
    __init__.py
    baz.py
Run Code Online (Sandbox Code Playgroud)
  • 如果您创建_init__.pyfoo/,foo.bar.baz将可用(如你所说).

  • 如果您添加foo/sys.path或使其通过PYTHONPATH=foo/,bar.baz将可用(注意没有父模块FOO).

  • 如果您编写自己的查找程序(和Loader),您可以加载任何您想要的文件,不管它在哪里.这给了你很大的力量.例如,看看stack-overflow-import,根据SO的搜索结果公开代码.