__init__.py 是做什么的?
- 2024-11-18 08:41:00
- admin 原创
- 11
问题描述:
__init__.py
Python 源目录中的用途是什么?
解决方案 1:
它曾经是软件包 (旧的、 3.3 之前的“常规软件包”,而不是较新的 3.3+“命名空间软件包” )的必需部分。
这是文档。
Python 定义了两种类型的包,即常规包和命名空间包。常规包是 Python 3.2 及更早版本中存在的传统包。常规包通常实现为包含文件的目录
__init__.py
。导入常规包时,__init__.py
会隐式执行此文件,并且其定义的对象将绑定到包命名空间中的名称。该__init__.py
文件可以包含任何其他模块可以包含的相同 Python 代码,并且 Python 会在导入模块时向其添加一些附加属性。
但只需单击链接,它包含一个示例、更多信息和命名空间包的解释(没有__init__.py
.
解决方案 2:
命名的文件__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
此答案基于此网页。
解决方案 3:
除了将目录标记为 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
,我可以使用下面的语法启动一个新会话。此代码在“数据库”包目录内部或外部执行都是一样的。
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
文件应该非常薄,以避免违反“显式优于隐式”的理念。
解决方案 4:
主要有两个原因__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)
解决方案 5:
该__init__.py
文件使 Python 将包含它的目录视为模块。
此外,这是模块中第一个被加载的文件,因此您可以使用它来执行每次加载模块时要运行的代码,或者指定要导出的子模块。
解决方案 6:
从 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 吗?
解决方案 7:
尽管 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
解决方案 8:
在 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
内容。
解决方案 9:
__init__.py
将会把它所在的目录视为可加载模块。
对于喜欢阅读代码的人,我把Two-Bit Alchemist 的评论放在这里。
$ 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
>>>
解决方案 10:
它便于导入其他 python 文件。当您将此文件放在包含其他 py 文件的目录(例如 stuff)中时,您可以执行类似 import stuff.other 的操作。
root\n stuff\n other.py
morestuff\n another.py
如果目录 stuff 中没有这个__init__.py
,您就无法导入 other.py,因为 Python 不知道 stuff 的源代码在哪里,也无法将其识别为包。
解决方案 11:
文件__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
解决方案 12:
__init__.py 允许将模块转换为包,而不会破坏 API 或创建多余的嵌套命名空间或私有模块*。当我想扩展命名空间时,这会很有帮助。
如果我有一个文件 util.py 包含
def foo():
...
然后用户将foo
访问
from util import foo
如果我想添加用于数据库交互的实用函数,并且希望它们在 下有自己的命名空间util
,我需要一个新目录*,并且为了保持 API 兼容性(以便from util import foo
仍然有效),我将其命名为 util/。我可以*将 util.py 移动到 util/,如下所示,
util/
__init__.py
util.py
db.py
在 util/__init__.py 中执行
from util import *
但这是多余的。我们不需要使用 util/util.py 文件,只需将 util.py 内容放在 __init__.py 中,用户就可以
from util import foo
from util.db import check_schema
我认为这很好地突出了包的 __init__.py 与模块util
的类似作用util
其他答案中也提到了这一点,但我想在这里强调一下
** 无需使用导入技巧。请注意,创建与文件同名的新包是行不通的,请参阅此
解决方案 13:
__init__.py
:它是位于包目录中的 Python 文件,在导入包或包中的模块时会调用它。您可以使用它来执行包初始化代码,即,每当导入包时,都会先执行 Python 语句,然后再执行此文件夹中的其他模块。它类似于 c 或 Java 程序的主函数,但它存在于 Python 包模块(文件夹)中,而不是核心 Python 文件中。__init__.py
当模块导入 Python 文件时,它还可以访问此文件中定义的全局变量。
例如,
我__init__.py
在一个名为的文件夹中有一个名为的文件pymodlib
,该文件包含以下语句:
print(f'Invoking __init__.py for {__name__}')
pystructures = ['for_loop', 'while__loop', 'ifCondition']
pymodlib
当我在解决方案模块或笔记本或 Python 控制台中导入此包时:
导入时会执行这两个语句。因此,在日志或控制台中,您将看到以下输出:
>>> import pymodlib
Invoking __init__.py for pymodlib
在 python 控制台的下一个语句中:我可以访问全局变量:
>> pymodlib.pystructures
它给出以下输出:
['for_loop', 'while__loop', 'ifCondition']
现在,从 Python 3.3 开始,此文件的使用已成为可选的,以使文件夹成为 Python 模块。因此,您可以跳过将其包含在 Python 模块文件夹中的步骤。
解决方案 14:
如果您使用的是 Python 2 并且想要加载文件的同级文件,您只需将文件的父文件夹添加到会话的系统路径中即可。它的行为与当前文件是初始化文件时的行为大致相同。
import os
import sys
dir_path = os.path.dirname(__file__)
sys.path.insert(0, dir_path)
此后,相对于文件目录的常规导入就可以正常工作。例如
import cheese
from vehicle_parts import *
# etc.
虽然通常情况下,你会希望使用正确的init .py 文件,但在处理遗留代码时,你可能会被困在例如一个硬编码的库中,该库仅用于加载特定文件。对于这些情况,这是一种替代方案。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件