Ist __init__.py für Pakete in Python 3.3+ nicht erforderlich?


193

Ich benutze Python 3.5.1. Ich habe das Dokument und den Paketabschnitt hier gelesen: https://docs.python.org/3/tutorial/modules.html#packages

Jetzt habe ich folgende Struktur:

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

module.py::

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

Jetzt, während in /home/wujek/Playground:

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

In ähnlicher Weise, jetzt zu Hause, Superordner von Playground:

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

Eigentlich kann ich alles Mögliche machen:

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

Warum funktioniert das? Ich obwohl es erforderlich sein , __init__.pyDateien in beide (leeren funktionieren würde) aund bfür module.pyimportierbar zu sein , wenn die Python - Pfad verweist auf den PlaygroundOrdner?

Dies scheint sich gegenüber Python 2.7 geändert zu haben:

~ $ 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

Mit __init__.pyin beiden ~/Playground/aund ~/Playground/a/bes funktioniert gut.

Antworten:


190

Python 3.3+ verfügt über implizite Namespace-Pakete , mit denen Pakete ohne __init__.pyDatei erstellt werden können.

Das Zulassen impliziter Namespace-Pakete bedeutet, dass die Anforderung zur Bereitstellung einer __init__.pyDatei vollständig gelöscht und beeinflusst werden kann.

Der alte Weg mit __init__.pyDateien funktioniert immer noch wie in Python 2.


10
Ich werde das Dokument lesen, aber es ist ein bisschen lang. Ist es möglich, schnell zusammenzufassen? Könnten Sie mir einfach sagen: Unterstützt es noch init .py oder ignoriert es sie vollständig? Wenn es sie unterstützt, was ist der Unterschied in der Funktionalität und warum diese Dualität?
Wujek

3
Das Tutorial sollte also wahrscheinlich aktualisiert werden. Ist ein Dokumentationsfehler dafür geöffnet?
Michel Samia

4
Ich bin immer noch verärgert, dass dies der Zen Of Python Zeile 2 trotzt : Explicit is better than implicit.....
JayRizzo

4
@ JayRizzo Aber: "Obwohl Praktikabilität Reinheit schlägt."
Mike Müller

18
@ JayRizzo IMO ist es noch expliziter. Manchmal macht es Init-Sachen __init__.py, manchmal nicht. Wenn ich in Python 3 diese Dinge brauche, erstelle ich einen neuen __init__.pymit spezifischem Code, sonst nicht. Dies ist praktisch, um visuell zu wissen, welche Pakete eine benutzerdefinierte Init haben. Stattdessen muss ich in Python 2 immer ein __init__.py(oft leeres) platzieren, wodurch eine große Anzahl von ihnen erstellt wird und es schließlich schwieriger wird, sich daran zu erinnern, wo Sie Ihren Init-Code platziert haben. Dies sollte auch passen "Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun."
Paolo

146

WICHTIG

@ Mikes Antwort ist richtig, aber zu ungenau. Es stimmt, dass Python 3.3+ implizite Namespace-Pakete unterstützt , mit denen ein Paket ohne __init__.pyDatei erstellt werden kann.

Dies gilt jedoch NUR für leere__init__.py Dateien. So LEER__init__.py - Dateien sind nicht mehr notwendig und kann weggelassen werden. Wenn Sie beim Importieren des Pakets oder eines seiner Module oder Unterpakete ein bestimmtes Initialisierungsskript ausführen möchten, benötigen Sie weiterhin ein__init__.py Datei. Dies ist eine großartige Antwort auf den Stapelüberlauf, warum Sie eine __init__.pyDatei verwenden möchten, um eine weitere Initialisierung durchzuführen, falls Sie sich fragen, warum dies in irgendeiner Weise nützlich ist.

Beispiel für die Verzeichnisstruktur:

  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")

BEISPIELE

Die folgenden Beispiele zeigen, wie das Initialisierungsskript ausgeführt wird, wenn das child_package oder eines seiner Module importiert wird.

Beispiel 1 :

from parent_package import child_package  # prints "from parent"

Beispiel 2 :

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

2
Angenommen, ich habe das run_script.pygleiche Verzeichnis wie parent_packagekann ich einfach wie from parent_package.child_package import child1ohne importieren __init__.py?
Mrgloom

Ist dies der Zweck, damit Sie child_package.some_function schreiben können, auch wenn some_function in childX.py definiert ist? Mit anderen Worten, es wird vermieden, dass der Benutzer die verschiedenen Dateien in child_package kennen muss. ?
Johnbakers

Ja, ich verstehe nicht, warum Sie machen würden child1.py, child2.pyanstatt nur ihren Code __init__direkt in .py zusammenzustellen.
Binki

Sollten die Importanweisungen __init__nicht relative Importe sein, dh from . import child1? Der absolute Import gibt mir ModuleNotFoundError(in Python 3.6)
Halbeard

5
Nach meiner Erfahrung wird selbst mit Python 3.3+ __init__.pymanchmal noch ein Leerzeichen benötigt, beispielsweise wenn Sie einen Unterordner als Paket bezeichnen möchten. Wenn ich zum Beispiel ausgeführt habe, hat python -m test.fooes nicht funktioniert, bis ich ein leeres __init__.pyunter dem Testordner erstellt habe. Und ich spreche hier von der Version 3.6.6!
Prahlad Yeri

6

Wenn Sie setup.pyin Ihrem Projekt haben und es darin verwenden find_packages(), ist es erforderlich, __init__.pyin jedem Verzeichnis eine Datei zu haben, damit Pakete automatisch gefunden werden.

Pakete werden nur erkannt, wenn sie eine __init__.pyDatei enthalten

UPD : Wenn Sie implizite Namespace-Pakete verwenden möchten, ohne diese __init__.pynur verwenden zu müssenfind_namespace_packages() stattdessen verwenden zu müssen

Docs


1

Ich würde sagen, dass man das __init__.pynur weglassen sollte, wenn man das implizite Namespace-Paket haben möchte . Wenn Sie nicht wissen, was es bedeutet, möchten Sie es wahrscheinlich nicht und sollten daher das __init__.pyEven in Python 3 weiterhin verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.