题 什么是__init__.py?


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


1418
2018-01-15 20:09


起源


根据以下评论@Rob_before_edits和 这个stackoverflow线程37139786, 看起来 在里面Python 3.3+不再需要.py。 - Jun


答案:


它是一个包的一部分。 这是文档。

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


979
2018-01-15 20:13



这意味着什么:“这样做是为了防止具有通用名称的目录(例如字符串)无意中隐藏稍后在模块搜索路径上出现的有效模块”? - Carl G
@CarlG Python搜索一个 目录列表 解析例如import语句中的名称。因为这些目录可以是任何目录,并且最终用户可以添加任意目录,所以开发人员必须担心碰巧与有效Python模块共享名称的目录,例如docs示例中的“string”。为了缓解这种情况,它会忽略不包含名为_ _ init _ _.py(无空格)的文件的目录,即使它是空白的。 - Two-Bit Alchemist
@CarlG试试这个。创建一个名为“datetime”的目录,并在其中创建两个空白文件,即init.py文件(带下划线)和datetime.py。现在打开一个解释器,导入sys和问题 sys.path.insert(0, '/path/to/datetime'),将路径替换为您刚刚创建的目录的路径。现在尝试类似的东西 from datetime import datetime;datetime.now()。你应该得到一个AttributeError(因为它现在正在导入你的空白文件)。如果您在不创建空白init文件的情况下重复这些步骤,则不会发生这种情况。这就是预防的目的。 - Two-Bit Alchemist
@DarekNędza如果您不能只打开Python解释器并发布问题,那么您的设置错误 from datetime import datetime 没有错误。这很好,一直到2.3版本! - Two-Bit Alchemist
@SWang:这是不对的: builtins 列出内置 功能 和 类,不是内置模块(参见 docs.python.org/3/tutorial/modules.html#the-dir-function)。如果要列出内置的 模块,做 import sys; print(sys.builtin_module_names) (参见 docs.python.org/3/library/sys.html#sys.builtin_module_names)。 - Maggyero


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

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

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

import spam.module

要么

from spam import module

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

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

import spam

基于 这个


598
2017-11-07 03:31



更新:文件 __init__.py 在Python 2.X下是必需的,并且在Python 2.7.12(我测试过它)中仍然需要它,但从(据称)Python 3.3开始不再需要它,并且在Python 3.4.3(我测试它)中不需要它。看到 stackoverflow.com/questions/37139786 更多细节。 - Rob_before_edits


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

一个例子

这是我的一个项目中的一个例子,我经常导入一个 sessionmaker 叫 Session 与我的数据库进行交互。我写了一个带有几个模块的“数据库”包:

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)

自从我定义 Session 在这里,我可以使用下面的语法开始一个新的会话。此代码与“database”包目录内部或外部执行的代码相同。

from database import Session
session = Session()

当然,这是一个小便利 - 另一种选择是定义 Session 在我的数据库包中的“create_session.py”这样的新文件中,使用以下命令启动新会话:

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 文件应该很薄,以避免违反“明确比隐含更好”的理念。


366
2017-09-24 10:38



engine, sessionmaker, create_engine,和 os 也都可以从中导入 database 现在......好像你已经弄乱了那个命名空间。 - ArtOfWarfare
@ArtOfWarfare,你可以使用 __all__ = [...] 限制导入的内容 import *。但除此之外,是的,你留下了一个凌乱的顶级命名空间。 - Nathan Gould


有两个主要原因 __init__.py

  1. 为方便起见:其他用户无需知道函数在包层次结构中的确切位置。

    your_package/
      __init__.py
      file1.py/
      file2.py/
        ...
      fileN.py
    
    # in __init__.py
    from file1 import *
    from file2 import *
    ...
    from fileN import *
    
    # in file1.py
    def add():
        pass
    

    其他人可以调用add()

    from your_package import add
    

    不知道file1,就像

    from your_package.file1 import add
    
  2. 如果你想要初始化的东西;例如,日志记录(应该放在顶层):

    import logging.config
    logging.config.dictConfig(Your_logging_config)
    

104
2018-04-08 08:29



哦,在阅读你的答案之前,我认为从它的位置明确地调用一个函数是一个很好的做法。 - Aaron


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

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


87
2018-01-15 20:22





从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-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
Python 3中的包不需要__init__.py吗? 


46
2017-10-12 06:36





在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函数。我们可以用 __init__.py 在subPackage_b中像这样:

__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

因此使用*导入,模块包受制于 __init__.py 内容。


44
2018-01-09 11:45





__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
>>> 

35
2018-01-03 17:41





__init__.py用于什么?

主要用途 __init__.py 是初始化Python包。演示这一点的最简单方法是查看标准Python模块的结构。

package/
    __init__.py
    file.py
    file2.py
    file3.py
    subpackage/
        __init__.py
        submodule1.py
        submodule2.py

正如你在上面的结构中所看到的,包含了 __init__.py 目录中的文件向Python解释器指示该目录应该被视为Python包

什么进来 __init__.py

__init__.py 可以是一个空文件,但它通常用于执行包所需的设置(导入东西,将东西加载到路径中等)。

你需要做的一件好事 __init__.py 是将选定的类,函数等导入包级别,以便可以方便地从包中导入它们。

在上面的示例中,我们可以说file.py具有类文件。所以我们没有任何东西 __init__.py 你会用这种语法导入:

from package.file import File

但是,您可以将文件导入到您的 __init__.py 使其在包级别上可用:

# in your __init__.py
from file import File

# now import File from package
from package import File

另一件事是在包级别上使用子包/模块 __all__ 变量。当说话者看到一个 __all__ 变量定义在 __init__.py 它导入了中列出的模块 __all__ 你做的变量:

from package import *

__all__是一个列表,其中包含您要使用import *导入的模块的名称*如果我们想要在子包中导入子模块,请再次查看上面的示例 __all__ 变量 subpackage/__init__.py 将会:

__all__ = ['submodule1', 'submodule2']

随着 __all__ 当你执行时,变量就像那样填充

from subpackage import *

它会导入submodule1和submodule2。

如你看到的 __init__.py 除了指示目录是模块的主要功能之外,它还非常有用。

参考


28
2017-12-17 06:09



你应该指出这个答案的原始来源: mikegrouchy.com/blog/2012/05/be-pythonic-__init__py.html - Ayushi Dalmia
@AyushiDalmia,我已经更新了我的答案。 - Chirag Maliwal


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

root\
    stuff\
         other.py

    morestuff\
         another.py

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


25
2018-01-15 20:18



这仅适用于所有子目录都是同一父目录的子目录的情况。 - gented


虽然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_methods


如果你更改了名称 methods.py 至 __init__.py 然后你可以使用 foo() 只需导入 main_methods

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

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


一些Python包实际上是这样做的。一个例子是 JSON,哪里跑 import json 实际上是导入 __init__.py 来自 json 包(在这里查看包文件结构):

源代码:  Lib/json/__init__.py


4
2018-05-12 15:41