【问题标题】:Why can I import successfully without __init__.py?为什么没有 __init__.py 可以成功导入?
【发布时间】:2016-06-22 17:39:06
【问题描述】:

__init__.py 到底有什么用?是的,我知道这个文件将一个目录变成了一个可导入的包。但是,请考虑以下示例:

project/
   foo/
      __init__.py
      a.py
      bar/
         b.py

如果我想将a导入b,我必须添加以下语句:

sys.path.append('/path_to_foo')
import foo.a

无论有没有__init__.py,这都会成功运行。但是,如果没有sys.path.append 语句,无论有没有__init__.py,都会出现“无模块”错误。这使得似乎只有系统路径很重要,而__init__.py 没有任何影响。

为什么没有__init__.py,这个导入工作?

【问题讨论】:

  • 如果你只是做import foopython需要something来导入,所以它基本上是导入那个文件夹的__init__文件。
  • 您需要__init__.py 才能执行import foo.bar。它的作用类似于类上的__init__ 方法。
  • 另外,__init__.py 是使其工作所必需的,如果您尝试仅删除文件,那么它将使用已编译的 __init__.pyc 文件,该文件可能位于 @987654338 @子文件夹,如果你也删除它,那么你会看到它是必要的。

标签: python import


【解决方案1】:

__init__.py与Python能否找到你的包无关。您运行代码的方式是默认情况下您的包不在搜索路径上,但如果您以不同方式运行它或以不同方式配置 PYTHONPATH,则不需要 sys.path.append。

__init__.py 曾经是创建包所必需的,在大多数情况下,您仍然应该提供它。不过,从 Python 3.3 开始,没有__init__.py 的文件夹可以被视为implicit namespace package 的一部分,implicit namespace package 是一种用于将包拆分到多个目录的功能。

在进口加工过程中,进口机械将继续 像在 Python 中那样遍历父路径中的每个目录 3.2.在为父路径中的每个目录查找名为“foo”的模块或包时:

  • 如果找到<directory>/foo/__init__.py,则导入并返回一个常规包。
  • 如果没有,但找到<directory>/foo.{py,pyc,so,pyd},则导入并返回一个模块。扩展的确切列表因平台而异 以及是否指定了 -O 标志。这里的清单是 代表。
  • 如果没有,但<directory>/foo被发现并且是​​一个目录,它被记录并且扫描继续在父目录中的下一个目录 路径。
  • 否则扫描会继续父路径中的下一个目录。

如果扫描完成但没有返回模块或包,并且在 至少记录一个目录,然后创建一个命名空间包。

【讨论】:

  • @TadhgMcDonald-Jensen:__path__ 自动构建。命名空间包不需要__init__.py,但带有__init__.py 的文件夹将优先于创建命名空间包。
  • 是的,我意识到在进一步阅读 PEP 后,我将相关部分添加到您的答案中,这样其他人就不必搜索文档来找到该部分。
【解决方案2】:

如果你真的出于某种原因想要避开__init__.py,你就不要sys.path。相反,创建一个模块对象并将其 __path__ 设置为目录列表。

【讨论】:

    【解决方案3】:

    如果我想将a导入b,我必须添加以下语句:

    不!你只会说:import foo.a。所有这些都是在您使用python -m main.module 一次运行整个包的情况下提供的,其中main.module 是整个应用程序的入口点。它导入所有其他模块,并且导入更多模块的模块将尝试从该项目的根目录中查找它们。例如,foo.bar.c 将导入为 foo.bar.b

    那么看来只有系统路径重要,init.py没有任何作用。

    仅当您从不在项目中的位置或 python 查找库的位置导入模块时,您才需要修改 sys.path。 __init__.py 不仅使文件夹看起来像一个包,它还做了一些更多的事情,比如将对象“导出”到外部世界 (__all__)

    【讨论】:

      【解决方案4】:

      当您导入某些内容时,它必须:

      1. 检索已加载的模块或
      2. 加载导入的模块

      当您执行import foo 并且python 在您的sys.path 上的文件夹中找到一个名为foo 的文件夹时,它将在该文件夹中查找__init__.py 被视为顶级模块。

      (请注意,如果包不在您的sys.path 上,那么您需要append 它的位置才能导入它。)

      如果不存在,它将在__pycache__ 文件夹中查找__init__.pyc 版本,如果也缺少该版本,则该文件夹foo 不被视为可加载的python 包。如果没有找到foo 的其他选项,则会引发ImportError。

      如果您也尝试删除__init__.pyc 文件,您会发现包的初始化脚本确实是必要的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-02-06
        • 2018-01-13
        • 1970-01-01
        • 1970-01-01
        • 2013-05-05
        • 2017-05-17
        • 2015-09-28
        • 2016-06-14
        相关资源
        最近更新 更多