什么是__init__.py?

Mat*_*Mat 2074 python module package python-packaging

什么是__init__.py一个Python源目录?

Lok*_*oki 1312

它是一个包的一部分.这是文档.

__init__.py需要这些文件使Python将目录视为包含包; 这样做是为了防止具有通用名称的目录,例如__init__.py无意中隐藏在模块搜索路径上稍后(更深)发生的有效模块.在最简单的情况下,__init__.py可以只是一个空文件,但它也可以执行包的初始化代码或设置__init__.py变量,稍后描述.

  • 这是什么意思:"这样做是为了防止具有通用名称的目录(例如字符串)无意中隐藏稍后在模块搜索路径上出现的有效模块"? (178认同)
  • @CarlG试试吧.创建一个名为"datetime"的目录,并在其中创建两个空白文件,即init.py文件(带下划线)和datetime.py.现在打开一个解释器,导入sys,并发出`sys.path.insert(0,'/ path/to/datetime')`,用你刚刚创建的目录路径替换该路径.现在尝试类似`from datetime import datetime; datetime.now()`.你应该得到一个AttributeError(因为它现在正在导入你的空白文件).如果要在不创建空白init文件的情况下重复这些步骤,则不会发生这种情况.这就是预防的目的. (173认同)
  • @CarlG Python搜索[目录列表](http://docs.python.org/2/tutorial/modules.html#the-module-search-path)来解析例如import语句中的名称.因为这些目录可以是任何目录,并且最终用户可以添加任意目录,所以开发人员必须担心碰巧与有效Python模块共享名称的目录,例如docs示例中的"string".为了缓解这种情况,它会忽略不包含名为_ _ init _ _.py(无空格)的文件的目录,即使它是空白的. (94认同)
  • @SWang:这是不正确的:`builtins`列出了内置*函数*和*类*,而不是内置模块(参见https://docs.python.org/3/tutorial/modules.html#the-dir -功能).如果要列出内置*模块*,请执行`import sys; print(sys.builtin_module_names)`(参见https://docs.python.org/3/library/sys.html#sys.builtin_module_names). (5认同)
  • @DarekNędza如果你不能只打开一个Python解释器并且没有错误地发出`from datetime import datetime`,你就会错误地设置错误.这很好,一直到2.3版本! (4认同)
  • @ Two-BitAlchemist,我刚刚注意到关于模块搜索路径的文档(https://docs.python.org/2/tutorial/modules.html#the-module-search-path),它说`解释器首先搜索对于具有该名称的内置模块.如果未找到,则会在变量sys.path`给出的目录列表中搜索名为spam.py的文件.如果是的话,不应该`from datetime import datetime`总是导入标准的`datetime`模块? (4认同)
  • @ Two-BitAlchemist使用from/import它显示`ImportError:在两种情况下都不能导入名称'datetime'`(有和没有`__init __.py`).PS.使用Python 3.4和IDLE. (3认同)
  • 我不是你们要做的,但是包的重点是`html.parser`和`email.parser`和`dateutil.parser`这样的模块都有唯一的名称而不是所有的名字只是`parser` (3认同)
  • @loki你可以把评论的相关部分移到你的帖子吗?跟一堆评论比编辑好的帖子要难得多. (3认同)
  • @ Two-Bit Alchemist你的文档和解释的链接很有帮助,但它留下了一个未回答的问题.我怎么能拥有一个只有一个模块"mymodule.py"的目录,其中包含一个函数定义"myfunc()",当我打开Python解释器并输入"import from mymodule myfunc"时,它不会抛出一个错误.该目录缺少__init__.py文件,但仍然正确导入mymodule. (2认同)
  • @ Bin,datetime不是内置模块,它是一个标准模块(https://docs.python.org/3/tutorial/modules.html#standard-modules).您可以通过'import builtins查看内置模块; DIR(内建)`". (2认同)

car*_*tos 772

命名__init__.py的文件用于将磁盘上的目录标记为Python包目录.如果你有文件

mydir/spam/__init__.py
mydir/spam/module.py
Run Code Online (Sandbox Code Playgroud)

并且mydir在您的路径上,您可以将代码导入module.py

import spam.module
Run Code Online (Sandbox Code Playgroud)

要么

from spam import module
Run Code Online (Sandbox Code Playgroud)

如果删除该__init__.py文件,Python将不再查找该目录中的子模块,因此导入模块的尝试将失败.

__init__.py文件通常是空的,但可以用更方便的名称导出包的选定部分,保存方便功能等.鉴于上面的例子,init模块的内容可以作为访问

import spam
Run Code Online (Sandbox Code Playgroud)

基于

  • 更新:文件`__init __.py`在Python 2.X下是必需的,并且在Python 2.7.12(我测试过)下仍然是必需的,但不再需要(据称)Python 3.3以上,并且在Python下不需要3.4.3(我测试过).有关详细信息,请参阅http://stackoverflow.com/questions/37139786/. (79认同)
  • 不要使用它。它是“命名空间”包,而不是常规包。名称空间包用于非常罕见的用例。您可能不需要知道何时使用它。只需使用__init__.py即可。 (2认同)
  • 但是,如果您有`setup.py`并且使用了`find_packages()`,则必须在每个目录中都有`__init __。py`。参见/sf/answers/3939412641/ (2认同)
  • 为什么`__init__.py`里面有`import spam`,它有什么帮助 (2认同)

Nat*_*uld 458

除了将目录标记为Python包并定义之外__all__,还__init__.py允许您在包级别定义任何变量.如果一个包定义了一些经常导入的东西,那么这样做通常会很方便.这种模式促进了对Pythonic的坚持"扁平比嵌套更好"的理念.

一个例子

以下是我的一个项目中的示例,其中我经常导入一个sessionmaker被调用Session来与我的数据库进行交互.我写了一个包含几个模块的"数据库"包:

database/
    __init__.py
    schema.py
    insertions.py
    queries.py
Run Code Online (Sandbox Code Playgroud)

__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)
Run Code Online (Sandbox Code Playgroud)

由于我Session在这里定义,我可以使用下面的语法开始一个新的会话.此代码与"database"包目录内部或外部执行的代码相同.

from database import Session
session = Session()
Run Code Online (Sandbox Code Playgroud)

当然,这是一个小小的便利 - 替代方法是Session在我的数据库包中的新文件中定义"create_session.py",并使用以下命令启动新会话:

from database.create_session import Session
session = Session()
Run Code Online (Sandbox Code Playgroud)

进一步阅读

有一个非常有趣的reddit线程,涵盖了__init__.py这里的适当用法:

http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/

大多数意见似乎是__init__.py文件应该非常薄,以避免违反"明确比隐含更好"的哲学.

  • @ArtOfWarfare,您可以使用`__all__ = [...]`来限制使用`import*`导入的内容.但除此之外,是的,你留下了凌乱的顶级命名空间. (9认同)
  • @NathanGould,您还可以使用默认情况下不通过“import *”导入的单前导下划线变量。例如:“import os as _os”并在“__init__.py”模块中使用“_os”代替“os”。 (4认同)
  • `engine`,`sessionmaker`,`create_engine`和`os`现在都可以从`database`导入...好像你已经弄乱了那个命名空间. (3认同)

fly*_*cee 204

有两个主要原因 __init__.py

  1. 为方便起见:其他用户无需知道函数在包层次结构中的确切位置.

    your_package/
      __init__.py
      file1.py
      file2.py
        ...
      fileN.py
    
    Run Code Online (Sandbox Code Playgroud)

    其他人可以调用add()

    # in __init__.py
    from file1 import *
    from file2 import *
    ...
    from fileN import *
    
    Run Code Online (Sandbox Code Playgroud)

    不知道file1,就像

    # in file1.py
    def add():
        pass
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果你想要初始化的东西; 例如,日志记录(应该放在顶层):

    from your_package import add
    
    Run Code Online (Sandbox Code Playgroud)

  • @Aerin 最好不要认为简短的陈述(或者在这种情况下,主观结论)总是正确的。从 `__init__.py` 导入有时可能有用,但并非总是有用。 (5认同)
  • 哦,在阅读答案之前,我认为从其位置显式调用一个函数是一个好习惯。 (3认同)
  • __init__.py 里面必须有什么? (2认同)

Can*_*der 104

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

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

  • 我认为 __init__.py 使 Python 将目录视为 *packages* 而不是 *modules*。请参阅 https://docs.python.org/3/tutorial/modules.html (7认同)
  • “所有包都是模块,但并非所有模块都是包”——很奇怪,但却是事实。 (4认同)

zee*_*vfu 80

从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
Run Code Online (Sandbox Code Playgroud)

参考:
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中的包不是必需的吗?

  • @RobertLugg 参见 https://dev.to/macet/don-t-omit-init-py-3hga (5认同)
  • 它是“命名空间”包。不要将它用于常规包装。 (4认同)
  • @methan,你能详细说明一下你的评论吗? (2认同)
  • 无论如何,这条评论解决了我一天工作 4 个小时的问题。无论出于何种原因,Spyder 今天早上决定不再导入我的模块。阅读此评论后,我删除了 __init__.py 文件,导入开始工作。谢谢@zeekvfu! (2认同)

Mar*_*ton 51

在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
Run Code Online (Sandbox Code Playgroud)

__init__.py可以是空的,只要它存在.它表示该目录应被视为包.当然,__init__.py也可以设置相应的内容.

如果我们在module_n1中添加一个函数:

def function_X():
    print "function_X in module_n1"
    return
Run Code Online (Sandbox Code Playgroud)

运行后:

>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()

function_X in module_n1 
Run Code Online (Sandbox Code Playgroud)

然后我们按照层次结构包并调用module_n1函数.我们可以__init__.py在subPackage_b中使用这样的:

__all__ = ['module_n2', 'module_n3']
Run Code Online (Sandbox Code Playgroud)

运行后:

>>>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
Run Code Online (Sandbox Code Playgroud)

因此,使用*导入,模块包受__init__.py内容限制.


Sim*_*mon 47

虽然Python在没有__init__.py文件的情况下工作,但您仍应包含一个.

它指定一个包应该被视为一个模块,因此包括它(即使它是空的).

还有一种情况您可能实际使用__init__.py文件:

想象一下,您有以下文件结构:

main_methods 
    |- methods.py
Run Code Online (Sandbox Code Playgroud)

methods.py包含在此:

def foo():
    return 'foo'
Run Code Online (Sandbox Code Playgroud)

要使用,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()
Run Code Online (Sandbox Code Playgroud)

也许你需要(或想要)保持methods.py在内部main_methods(例如运行时/依赖)但你只想导入main_methods.


如果更改的名称methods.py__init__.py那么你可以使用foo()由只导入main_methods:

import main_methods
print(main_methods.foo()) # Prints 'foo'
Run Code Online (Sandbox Code Playgroud)

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


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

源代码: Lib/json/__init__.py


B.M*_*.W. 38

__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
>>> 
Run Code Online (Sandbox Code Playgroud)


Epi*_*aph 29

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

root\
    stuff\
         other.py

    morestuff\
         another.py
Run Code Online (Sandbox Code Playgroud)

如果没有这个__init__.py目录内容,你就无法导入other.py,因为Python不知道东西的源代码在哪里,也无法将其识别为包.

  • 我在我的项目(python 3.4)中具有相同的结构,但是我无法使another.py看到other.py。我应该如何导入?从root.stuff导入其他?它可以在VSCode调试模式下工作,但不能在命令行中工作。有任何想法吗? (2认同)

Ale*_*ine 9

An __init__.py file makes imports easy. When an __init__.py is present within a package, function a() can be imported from file b.py like so:

from b import a
Run Code Online (Sandbox Code Playgroud)

Without it, however, you can't import directly. You have to amend the system path:

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

from b import a
Run Code Online (Sandbox Code Playgroud)


Joe*_*ley 7

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

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

def foo():
    ...
Run Code Online (Sandbox Code Playgroud)

然后用户将foo访问

from util import foo
Run Code Online (Sandbox Code Playgroud)

如果我想添加用于数据库交互的实用程序函数,并且我希望它们在 下有自己的命名空间util,我将需要一个新目录**,并保持 API 兼容性(以便from util import foo仍然有效),我将调用它实用程序/。我可以像这样将 util.py 移动到 util/ 中,

def foo():
    ...
Run Code Online (Sandbox Code Playgroud)

并在 util/__init__.py 中执行

from util import *
Run Code Online (Sandbox Code Playgroud)

但这是多余的。我们可以将 util.py 内容放入 __init__.py 中,而不是使用 util/util.py 文件,用户现在可以

from util import foo
from util.db import check_schema
Run Code Online (Sandbox Code Playgroud)

我认为这很好地突出了包的 __init__.py 如何以与模块util类似的方式运行util

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