__init__.py 是做什么用的?
-
19-08-2019 - |
题
什么是 __init__.py
在Python源目录中?
解决方案
它曾经是一个封装的必要部分(老,预-3.3 “正规套餐” ,不新3.3+“命名空间包“)。
的Python定义了两种类型的包,包定期和命名空间的包。普通包装是传统的包,因为它们在Python 3.2和更早的版本存在。一个普通的封装通常被实现为包含
__init__.py
文件的目录。当一个普通包是进口的,这__init__.py
文件被隐式执行,它定义了对象绑定到包的名称空间的名称。该__init__.py
文件可以包含相同的Python代码,任何其他组件可以包含,和Python将一些额外的属性添加到当它被导入的模块。
但只需点击链接,它包含了一个例子,更多的信息,并命名包的说明,不__init__.py
那种包。
其他提示
文件名为__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
基于此
在除了标记的目录作为Python包并限定__all__
,的 __init__.py
允许定义在封装级的任何变量。强>这样做往往是方便的,如果一个包定义的东西,将被导入经常,在API般的时尚。这种模式促进坚持Python化“扁平比嵌套更好”的理念。
一个例子
下面是我的项目,我在其中频繁导入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
,我可以使用下面的语法开始一个新会话。该代码将是从内部或外部“数据库”包目录的执行相同。
from database import Session
session = Session()
当然,这是一个小便利 - 的替代方案是在像在我的数据库包“create_session.py”的新的文件来定义Session
,以及使用启动新的会话:
from database.create_session import Session
session = Session()
进一步阅读
这里有覆盖__init__.py
的适当用途一个非常有趣的书签交易螺纹:
http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/
在大多数人看来似乎是__init__.py
文件应该是非常薄的,以避免违反“显胜于隐”的理念。
主要有2个原因 __init__.py
为了方便:其他用户不需要知道您的函数在包层次结构中的确切位置。
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
如果你想要初始化一些东西;例如,日志记录(应放在顶层):
import logging.config logging.config.dictConfig(Your_logging_config)
在__init__.py
文件使得它含有作为模块Python视目录。
此外,这是在一个模块中要加载的第一个文件,因此可以使用它来执行要每一个模块被加载时运行,或指定要导出的子模块的代码。
从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 吗?
在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
内容。
虽然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
__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
>>>
它便于导入其他蟒文件。当你放在这个文件在目录(说的东西)含有其他PY文件,那么你可以这样做进口stuff.other。
root\
stuff\
other.py
morestuff\
another.py
如果没有这个__init__.py
目录里面的东西,你不能导入other.py,因为Python不知道在哪里的东西源代码,无法将其识别为一个包。
这是__init__.py
文件使其进口容易。当__init__.py
是一个包内时,功能a()
可以从文件b.py
被导入像这样:
from b import a
如果没有它,但是,你不能直接导入。你必须修改系统路径:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a