3111

__init__.pyPython 源目录中的用途是什么?

4

12 回答 12

1777

它曾经是包的必需部分(旧的,3.3 之前的“常规包”,而不是较新的 3.3+“命名空间包”)。

这是文档。

Python 定义了两种类型的包,常规包和命名空间包。常规包是 Python 3.2 及更早版本中存在的传统包。常规包通常实现为包含__init__.py文件的目录。当一个常规包被导入时,这个__init__.py文件被隐式执行,它定义的对象被绑定到包命名空间中的名字。该__init__.py文件可以包含任何其他模块可以包含的相同 Python 代码,并且 Python 会在导入模块时为其添加一些附加属性。

但只需单击链接,它包含一个示例、更多信息和对命名空间包的解释,即没有__init__.py.

于 2009-01-15T20:13:24.987 回答
1054

命名文件__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

基于

于 2010-11-07T03:31:14.820 回答
583

除了将目录标记为 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文件应该非常薄,以避免违反“显式优于隐式”的理念。

于 2013-09-24T10:38:34.920 回答
407

有2个主要原因__init__.py

  1. 为方便起见:其他用户不需要知道您的函数在包层次结构(文档)中的确切位置。

    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. 如果你想初始化一些东西;例如,日志记录(应该放在顶层):

     import logging.config
     logging.config.dictConfig(Your_logging_config)
    
于 2015-04-08T08:29:37.057 回答
157

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

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

于 2009-01-15T20:22:58.243 回答
120

从 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/
是__init__。 Python 3 中的包不需要 py 吗?

于 2016-10-12T06:36:59.080 回答
94

尽管 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.


如果您更改了 to 的名称,methods.py__init__.py只需foo()导入即可使用main_methods

import main_methods
print(main_methods.foo()) # Prints 'foo'

这是有效的,因为__init__.py它被视为包的一部分。


一些 Python 包实际上是这样做的。一个示例是JSON,其中运行import json实际上是__init__.pyjson包中导入(请参阅此处的包文件结构):

源代码: Lib/json/__init__.py

于 2018-05-12T15:41:25.780 回答
64

在 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内容为准。

于 2014-01-09T11:45:10.847 回答
46

__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
>>> 
于 2015-01-03T17:41:14.480 回答
40

它有助于导入其他 python 文件。当您将此文件放在包含其他 py 文件的目录(例如东西)中时,您可以执行诸如 import stuff.other 之类的操作。

root\
    stuff\
         other.py

    morestuff\
         another.py

如果在目录 stuff 中没有此__init__.py内容,则无法导入 other.py,因为 Python 不知道 stuff 的源代码在哪里,并且无法将其识别为包。

于 2009-01-15T20:18:32.840 回答
12

文件使__init__.py导入变得容易。当__init__.py包中存在an 时,a()可以从文件中导入函数,b.py如下所示:

from b import a

但是,没有它,您将无法直接导入。您必须修改系统路径:

import sys
sys.path.insert(0, 'path/to/b.py')

from b import a
于 2019-05-25T02:42:56.847 回答
4

__init__.py 允许的一件事是将模块转换为包而不破坏 API 或创建无关的嵌套命名空间或私有模块*。当我想扩展命名空间时,这会有所帮助。

如果我有一个文件 util.py 包含

def foo():
    ...

然后用户将foo访问

from util import foo

如果我想为数据库交互添加实用程序函数,并且我希望它们在 下有自己的命名空间util,我需要一个新目录**,并保持 API 兼容性(这样from util import foo仍然有效),我会调用它实用程序/。我可以像这样将 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模块的方式运行

*这在其他答案中有所暗示,但我想在这里强调它
**没有使用进口体操。请注意,创建与文件同名的新包将不起作用,请参阅

于 2020-07-19T21:37:17.557 回答