module - __init__.py是干什么的?

  显示原文与译文双语对照的内容

在一个源 directory, python __init__.py 对于是什么?

时间:

这是软件包的一部分。 这里是文档。

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

名为 __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 文件通常是空的,但可以用来在更方便的名称下导出选中的部分,保留方便的函数,等等,模块的内容可以被访问

 
import spam

 

基于 http://effbot.org/pyfaq/what-is-init-py-used-for.htm

除了将目录标记为 python 包并定义 __all__ 之外, __init__.py 允许你在包级别定义任何变量。 在一个 API-like fashion, 这样做通常是很方便的如果包定义了将要导入的东西经常,. 这种模式促进了 Pythonic"平面比嵌套的好"哲学的坚持。

一个示例

这里有我database,是一个例子来自我的一个项目中,我经常在其中导入一个 sessionmaker 称为 Session 来交互React起来, 我编写了一个带有几个模块的"数据库"包:


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,我可以使用下面的语法开始一个新的会话。 这里代码将在"数据库"包目录的内部或者外部执行。


from database import Session
session = Session()

使用,当然,这只是一个小喜欢的方便的替代办法是定义在一个新文件中 Session --" create_session.py"在我的数据库包,并开始新 sessions:


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 文件应该非常薄,以避免违反"explicit比隐式好"原则。

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

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

这里提供了对 __init__.py 用法的一个很好的解释:http://mikegrouchy.com/blog/2012/05/be-pythonic-__init__py.html

它方便导入其他 python 文件。 当你将这里文件放在包含其他( 说出内容) 文件的目录中时,你可以执行类似导入 stuff.other.的操作


root
 stuff
 other.py

 morestuff
 another.py

如果目录中没有这个 __init__.py,你就无法导入 other.py,,因为 python 不知道源代码的来源,并且无法将它的识别为软件包。

在 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 内容的影响。

  1. 为了方便:其他用户不需要知道你的函数'确切位置 location 。

    
    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. 放置用于初始化的东西。例如 logging(this should put in the top level):

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

__init__.py 将把它所在的目录视为可以装入模块。

对于喜欢阅读代码的人,我在这里放置了 Two-Bit的 。comment注释。


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

...