__init__.py在Python源目录中用于什么?
当前回答
除了将目录标记为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文件应该非常薄,以避免违反“显式优于隐式”的原则。
其他回答
__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模块文件夹中。
__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文件使导入变得容易。当包中存在__init__.py时,可以从文件b.py导入函数a(),如下所示:
from b import a
但是,如果没有它,就不能直接导入。您必须修改系统路径:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a
它有助于导入其他python文件。当您将此文件放置在包含其他py文件的目录(比如stuff)中时,可以执行类似importstuff.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函数。我们可以在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内容的约束。