Python 3.3+中的软件包不需要__init__.py吗


193

我正在使用Python 3.5.1。我在这里阅读了文档和包部分:https : //docs.python.org/3/tutorial/modules.html#packages

现在,我具有以下结构:

/home/wujek/Playground/a/b/module.py

module.py

class Foo:
    def __init__(self):
        print('initializing Foo')

现在,在/home/wujek/Playground

~/Playground $ python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x100a8f0b8>

同样,现在在家里,超级文件夹Playground

~ $ PYTHONPATH=Playground python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x10a5fee10>

实际上,我可以做各种事情:

~ $ PYTHONPATH=Playground python3
>>> import a
>>> import a.b
>>> import Playground.a.b

为什么这样做?我虽然__init__.py两者都需要文件(空文件可以工作),a并且bmodule.py在Python路径指向Playground文件夹时可导入?

这似乎与Python 2.7有所不同:

~ $ PYTHONPATH=Playground python
>>> import a
ImportError: No module named a
>>> import a.b
ImportError: No module named a.b
>>> import a.b.module
ImportError: No module named a.b.module

随着__init__.py在这两个~/Playground/a~/Playground/a/b它工作正常。

Answers:


190

Python 3.3+具有隐式命名空间包,允许它创建不带__init__.py文件的包。

允许隐式命名空间包意味着可以完全放弃提供__init__.py文件的要求,并使其受到影响。

__init__.py文件的旧方法仍然可以在Python 2中使用。


10
我将阅读该文档,但是有点长。是否可以快速总结?您能否告诉我:它仍然支持init .py,还是完全忽略它们?如果它确实支持它们,那么功能上有什么区别,为什么会有这种双重性?
wujek

3
因此,本教程可能应该进行更新。是否为此打开了文档错误?
米歇尔·萨米亚

4
我仍然Zen Of PythonExplicit is better than implicit.
不满意

4
@JayRizzo但是:“尽管实用胜过纯洁。”
MikeMüller18年

18
@JayRizzo IMO更加明确。有时它碰巧在中做初始化操作__init__.py,有时则不行。在Python 3中,当我需要这些东西时,我会__init__.py使用特定的代码创建一个新代码,否则就不需要。从视觉上很容易知道哪些包具有自定义的init。取而代之的是,在python 2中,我总是必须放置一个__init__.py(通常为空),制作大量的它们,最后更难记住您放置初始化代码的位置。这也应该适合“应该有一种-最好只有一种-显而易见的方法”。
Paolo

146

重要

@Mike的回答是正确的,但过于精确。确实,Python 3.3+支持隐式命名空间包,这允许它创建不带__init__.py文件的包。

但是,这仅适用于EMPTY__init__.py文件。因此,EMPTY__init__.py文件不再是必需的,可以省略。如果要在导入软件包或其任何模块或子软件包时运行特定的初始化脚本,则仍然需要__init__.py文件。这是一个很好的Stack Overflow答案,它说明了为什么您想使用__init__.py文件进行一些进一步的初始化,以防您想知道为什么这样做有任何用处。

目录结构示例:

  parent_package/
     __init__.py            <- EMPTY, NOT NECESSARY in Python 3.3+
     child_package/
          __init__.py       <- STILL REQUIRED if you want to run an initialization script
          child1.py
          child2.py
          child3.py

parent_package/child_package/__init__.py

print("from parent")

例子

以下示例演示了如何在执行初始化脚本时执行初始化脚本。 child_package导入或其中一个模块。

范例1

from parent_package import child_package  # prints "from parent"

范例2

from parent_package.child_package import child1  # prints "from parent"

2
假设我的run_script.py目录与之相同,parent_package那么我可以像from parent_package.child_package import child1没有这样导入__init__.py吗?
mrgloom

这样做的目的是,即使在childX.py中定义了some_function,您也可以编写child_package.some_function?换句话说,它避免了要求用户了解child_package中的不同文件??
johnbakers

是的,我不知道为什么要这样做child1.pychild2.py而不仅仅是将他们的代码__init__直接放入.py中。
宾基

导入中的语句不应该__init__是相对导入from . import child1吗?绝对导入使我ModuleNotFoundError(在Python 3.6中)
Halbeard

5
以我的经验,即使使用python 3.3+,__init__.py有时还是需要为空,例如当您要将子文件夹作为包引用时。例如,如果我运行python -m test.foo它,则必须等到__init__.py在测试文件夹下创建一个空白后才能运行。我在这里说的是3.6.6版本!
Prahlad Yeri

6

如果你有 setup.py在项目中并在其中使用find_packages(),则必须__init__.py在每个目录中都有一个文件,以便自动找到软件包。

程序包仅在包含__init__.py文件的情况下才被识别

UPD:如果你想使用隐式命名空间包,而__init__.py你只需要使用find_namespace_packages()替代

文件


1

我要说的是,__init__.py只有一个人想要拥有隐式命名空间包时,才应该省略它。如果您不知道这意味着什么,则可能不想要它,因此您应该__init__.py在Python 3中继续使用even。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.