__init__.py在Python源目录中用于什么?


它曾经是包的必需部分(旧的3.3之前的“常规包”,而不是更新的3.3+“命名空间包”)。

这是文档。

Python定义了两种类型的包,常规包和命名空间包。常规包是Python 3.2和更早版本中存在的传统包。常规包通常实现为包含__init__.py文件的目录。导入常规包时,将隐式执行__init__.py文件,它定义的对象将绑定到包的命名空间中的名称。__init__.py文件可以包含任何其他模块都可以包含的Python代码,并且Python将在导入模块时向模块添加一些附加属性。

但只需单击链接,它包含一个示例、更多信息和对命名空间包的解释,这是一种没有__init__.py的包。


它有助于导入其他python文件。当您将此文件放置在包含其他py文件的目录(比如stuff)中时,可以执行类似importstuff.other的操作。

root\
    stuff\
         other.py

    morestuff\
         another.py

如果在目录中没有这个__init__.py,您就无法导入other.py,因为Python不知道这些东西的源代码在哪里,也无法将其识别为一个包。


__init__.py文件使Python将包含它的目录视为模块。

此外,这是模块中要加载的第一个文件,因此您可以使用它来执行每次加载模块时要运行的代码,或者指定要导出的子模块。


名为__init__.py的文件用于将磁盘上的目录标记为Python包目录。如果你有文件

mydir/spam/__init__.py
mydir/spam/module.py

mydir在您的路径上,您可以将module.py中的代码导入为

import spam.module

or

from spam import module

如果删除__init__.py文件,Python将不再在该目录中查找子模块,因此导入模块的尝试将失败。

__init__.py文件通常为空,但可用于以更方便的名称导出包的选定部分,保存方便函数等。给定上面的示例,init模块的内容可以访问为

import spam

基于此


除了将目录标记为Python包并定义__all__之外,__init__.py还允许您在包级别定义任何变量。如果包以类似API的方式定义了将频繁导入的内容,那么这样做通常很方便。这种模式促进了对Pythonic“扁平优于嵌套”哲学的坚持。

一个例子

这里是我的一个项目中的一个示例,其中我经常导入一个名为Session的sessionmaker来与我的数据库交互。我编写了一个包含几个模块的“数据库”包:

database/
    __init__.py
    schema.py
    insertions.py
    queries.py

我的__init__.py包含以下代码:

import os

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)

因为我在这里定义了会话,所以可以使用下面的语法启动新会话。该代码将与从“数据库”包目录内部或外部执行的代码相同。

from database import Session
session = Session()

当然,这只是一个小小的方便——另一种选择是在数据库包中的一个新文件(如“create_Session.py”)中定义Session,然后使用以下命令启动新会话:

from database.create_session import Session
session = Session()

进一步阅读

这里有一个非常有趣的reddit线程,介绍了__init__.py的适当用法:

http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/

大多数人认为__init__.py文件应该非常薄,以避免违反“显式优于隐式”的原则。


在Python中,包的定义非常简单。与Java一样,层次结构和目录结构是相同的。但是你必须在包中包含__init__.py。我将用下面的示例解释__init__.py文件:

package_x/
|--  __init__.py
|--    subPackage_a/
|------  __init__.py
|------  module_m1.py
|--    subPackage_b/
|------  __init__.py
|------  module_n1.py
|------  module_n2.py
|------  module_n3.py

__init__.py可以是空的,只要它存在。它表示目录应被视为一个包。当然,__init__.py也可以设置适当的内容。

如果我们在module_n1中添加函数:

def function_X():
    print "function_X in module_n1"
    return

运行后:

>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()

function_X in module_n1 

然后我们遵循层次结构包并调用module_n1函数。我们可以在subPackage_b中使用__init__.py,如下所示:

__all__ = ['module_n2', 'module_n3']

运行后:

>>>from package_x.subPackage_b import * 
>>>module_n1.function_X()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named module_n1

因此,使用*importing,模块包受__init__.py内容的约束。


__init__.py将其所在的目录视为可加载模块。

对于喜欢阅读代码的人,我将二位炼金术士的评论放在这里。

$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$ 
$ rm /tmp/mydir/spam/__init__.py*
$ 
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>> 

__init__.py有两个主要原因

为了方便:其他用户不需要知道您的函数在包层次结构(文档)中的确切位置。您的程序包(_P)/__初始__.py文件1.py文件2.py...文件N.py#在__init__.py中从.file1导入*从.file2导入*...从.fileN导入*#在file1.py中def add():通过然后其他人可以调用add()从您的_package导入添加不知道file1的内部函数,例如从您的_package.file1导入添加如果你想初始化一些东西;例如,日志记录(应该放在顶层):导入logging.configlogging.config.dictConfig(Your_logging_config)


自Python 3.3以来,__init__.py不再需要将目录定义为可导入的Python包。

检查PEP 420:隐式命名空间包:

对不需要__init__.py标记文件并且可以自动跨越多个路径段的包目录的本地支持(受PEP 420中描述的各种第三方命名空间包方法的启发)

测试如下:

$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

参考文献:https://docs.python.org/3/whatsnew/3.3.html#pep-420个隐式命名空间包https://www.python.org/dev/peps/pep-0420/Python 3中的包是否不需要__init__.py?


尽管Python在没有__init__.py文件的情况下工作,但仍应包含一个。

它指定目录应被视为一个包,因此包含它(即使它是空的)。

还有一种情况是,您可能实际使用__init__.py文件:

假设您具有以下文件结构:

main_methods 
    |- methods.py

而methods.py包含以下内容:

def foo():
    return 'foo'

要使用foo(),您需要以下选项之一:

from main_methods.methods import foo # Call with foo()
from main_methods import methods # Call with methods.foo()
import main_methods.methods # Call with main_methods.methods.foo()

也许您需要(或希望)将methods.py保存在main_methods(例如运行时/依赖项)中,但您只希望导入main_method。


如果将methods.py的名称更改为__init__.py,则可以通过导入main_methods来使用foo():

import main_methods
print(main_methods.foo()) # Prints 'foo'

这是因为__init__.py被视为包的一部分。


一些Python包实际上做到了这一点。一个例子是JSON,其中运行import JSON实际上是从JSON包中导入__init__.py(请参阅此处的包文件结构):

源代码:Lib/json/__init__.py


__init__.py文件使导入变得容易。当包中存在__init__.py时,可以从文件b.py导入函数a(),如下所示:

from b import a

但是,如果没有它,就不能直接导入。您必须修改系统路径:

import sys
sys.path.insert(0, 'path/to/b.py')

from b import a

__init__.py允许的一件事是将模块转换为包,而不破坏API或创建无关的嵌套命名空间或私有模块*。这有助于我扩展命名空间。

如果我有一个包含

def foo():
    ...

然后用户将使用

from util import foo

如果我想为数据库交互添加实用程序函数,并且希望它们在util下有自己的命名空间,那么我需要一个新目录**,并且为了保持API兼容性(这样从util import foo仍然可以工作),我将其称为util/。我可以像这样将util.py移动到util/中,

util/
  __init__.py
  util.py
  db.py

在util/__init__.py中

from util import *

但这是多余的。我们可以将util.py内容放在__init__.py中,而不是使用util/util.py文件,用户现在可以

from util import foo
from util.db import check_schema

我认为这很好地突出了util包的__init__.py的作用方式与util模块类似

*这在其他答案中有所暗示,但我想在这里强调一下**没有采用进口体操。请注意,创建与文件同名的新包是行不通的,请参见


__init__.py:它是一个在包目录中找到的Python文件,在导入包或包中的模块时调用。您可以使用它来执行包初始化代码,即每当导入包时,在执行此文件夹中的其他模块之前,首先执行python语句。它类似于c或Java程序的主函数,但它存在于Python包模块(文件夹)中,而不是核心Python文件中。它还可以访问__init__.py文件中定义的全局变量,就像将模块导入Python文件一样。

例如。我在一个名为pymodlib的文件夹中有一个__init__.py文件,该文件包含以下语句:

print(f'Invoking __init__.py for {__name__}')
pystructures = ['for_loop', 'while__loop', 'ifCondition']

当我在解决方案模块、笔记本或python控制台中导入此包pymodlib时:这两条语句在导入时执行。因此,在日志或控制台中,您将看到以下输出:

>>> import pymodlib
Invoking __init__.py for pymodlib

在python控制台的下一条语句中:我可以访问全局变量:

>> pymodlib.pystructures

它给出以下输出:

['for_loop', 'while__loop', 'ifCondition']

现在,从Python3.3开始,可以选择使用该文件来使文件夹成为Python模块。因此,您可以跳过将其包含在python模块文件夹中。


如果您使用的是Python 2,并且希望加载文件的同级文件,那么只需将文件的父文件夹添加到会话的系统路径中即可。它的行为与当前文件是init文件的情况大致相同。

import os
import sys
dir_path = os.path.dirname(__file__)
sys.path.insert(0, dir_path)

之后,相对于文件目录的常规导入将正常工作。例如。

import cheese
from vehicle_parts import *
# etc.

一般来说,您希望使用一个合适的init.py文件,但在处理遗留代码时,您可能会遇到f.ex.一个硬编码的库来加载特定文件,而不是其他文件。对于这些情况,这是一种选择。