__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
此导入工作?
答案 0 :(得分:9)
__init__.py
与Python是否可以找到您的包无关。您的代码运行方式默认情况下您的软件包不在搜索路径上,但如果您以不同的方式运行它或以不同的方式配置PYTHONPATH
,则sys.path.append
将不再必需
__init__.py
创建一个包,在大多数情况下,你仍然应该提供它。但是,从Python 3.3开始,没有__init__.py
的文件夹可以被视为implicit namespace package的一部分,这是一个跨多个目录拆分包的功能。
在导入处理期间,导入机器将继续 迭代父路径中的每个目录,就像在Python中一样 3.2。在寻找名为“foo”的模块或包时,对于父路径中的每个目录:
- 如果找到
<directory>/foo/__init__.py
,则会导入并返回常规包。- 如果没有,但找到
<directory>/foo.{py,pyc,so,pyd}
,则会导入并返回模块。扩展名的确切列表因平台而异 以及是否指定了-O标志。这里的清单是 代表。- 如果没有,但找到
<directory>/foo
并且是一个目录,则会记录,并继续扫描父目录中的下一个目录 路径。- 否则,扫描将继续执行父路径中的下一个目录。
如果扫描完成而未返回模块或包,则 at 记录了至少一个目录,然后创建了一个命名空间包。
答案 1 :(得分:1)
如果我要将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__
)
答案 2 :(得分:0)
如果确实出于某种原因想要避免__init__.py
,则不要sys.path
。而是创建一个模块对象并将其__path__
设置为目录列表。
答案 3 :(得分:0)
当你导入它必须的东西时:
当您执行import foo
并且python在foo
的文件夹中找到名为sys.path
的文件夹时,它会在该文件夹中查找__init__.py
被视为顶级模块。
(请注意,如果包裹不在sys.path
上,那么您需要append
它的位置才能导入它。)
如果不存在,它将在__init__.pyc
文件夹中查找__pycache__
版本,如果还缺少,则该文件夹foo
不被视为可加载的python包。如果找不到foo
的其他选项,则会引发ImportError
。
如果您尝试删除__init__.pyc
文件,您将看到确实需要包的初始化程序脚本。