在Python源代码目录中,init__.py
是用来做什么的?
它曾经是一个包的必要部分(旧的、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
基于[本][1]
除了将一个目录标记为Python包并定义"all"之外,__init__.py
还允许你在包级别定义任何变量。如果一个包定义了一些将被频繁导入的东西,那么这样做通常是很方便的,以一种类似于API的方式。
这种模式促进了Pythonic "flat is better than nested".哲学的遵守。
哲学。
下面是我的一个项目中的例子,在这个项目中,我经常导入一个叫做 "会话制作者 "的 "会话 "来与我的数据库进行交互。 我写了一个"数据库" 包,里面有几个模块。
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"。 这样的文件中定义 "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
主要有2个原因。
你的软件包/
__init__.py
file1.py
file2.py
...
fileN.py
#在__init__.py中
从file1导入*
从file2导入*
...
从fileN导入*
# 在file1.py中
def add():
pass
那么其他人就可以通过以下方式调用add()
从 your_package 导入 add
而不知道file1,比如
从 your_package.file1 中导入 add
import logging.config logging.config.dictConfig(Your_logging_config)
自 Python 3.3 起,__init__.py
不再需要定义目录为可导入的 Python 包。
检查 [PEP 420: 隐式命名空间包][1]。
原生支持不需要
__init__.py
标记文件并能自动跨越多个路径段的包目录 (受各种第三方命名空间包方法的启发,如 [PEP 420][2] 所述)
[1]: https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages [2]: https://www.python.org/dev/peps/pep-0420/
这里'是测试。
$ 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/ https://stackoverflow.com/questions/37139786/is-init-py-not-required-for-packages-in-python-3
在Python中,包的定义非常简单。
和 Java 一样,层次结构和目录结构都是一样的,但你必须在包里有 __init__.py
。
但是你必须在包中有__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
然后我们按照层次包,调用模块_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
因此,使用*导入,模块包受__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
,那么只要导入main_methods
就可以使用foo()
。
import main_methods
print(main_methods.foo()) # Prints 'foo'
这是因为__init__.py
被视为包的一部分。
有些 Python 包实际上是这样做的。 一个例子是[JSON][1],运行 "import json "实际上是从 "json "包中导入"init.py"([见这里的包文件结构][2])。
源代码:
Lib/json/__init__.py
。
[1]:https://docs.python.org/3/library/json.html [2]:https://github.com/python/cpython/tree/3.6/Lib/json
__init__.py
会把它所在的目录当作一个可加载模块。
对于喜欢看代码的人,我把Two-Bit Alchemist's的注释放在这里。
$ 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
>>>