it-swarm.com.de

Hinzufügen von Code zu __init__.py

Ich schaue mir an, wie das Modellsystem in Django funktioniert und habe etwas bemerkt, das ich nicht verstehe.

Ich weiß, dass Sie eine leere __init__.py - Datei erstellen, um anzugeben, dass das aktuelle Verzeichnis ein Paket ist. Und dass Sie eine Variable in __init__.py Setzen können, damit der Import * richtig funktioniert.

Aber Django fügt eine Reihe von from ... import ... -Anweisungen hinzu und definiert eine Reihe von Klassen in __init__.py. Gibt es einen Grund, der diesen Code in __init__.py Erfordert?

83
Erik

Alle Importe in __init__.py Werden verfügbar gemacht, wenn Sie das Paket (Verzeichnis) importieren, das es enthält.

Beispiel:

./dir/__init__.py:

import something

./test.py:

import dir
# can now use dir.something

BEARBEITEN: Ich habe vergessen zu erwähnen, dass der Code in __init__.py Ausgeführt wird, wenn Sie zum ersten Mal ein Modul aus diesem Verzeichnis importieren. Daher ist es normalerweise ein guter Ort, um einen Initialisierungscode auf Paketebene einzufügen.

EDIT2: dgrant wies auf eine mögliche Verwirrung in meinem Beispiel hin. In __init__.pyimport something Kann jedes Modul importiert werden, das nicht aus dem Paket benötigt wird. Zum Beispiel können wir es durch import datetime Ersetzen, dann funktionieren in unserer obersten Ebene test.py Beide Schnipsel:

import dir
print dir.datetime.datetime.now()

und

import dir.some_module_in_dir
print dir.datetime.datetime.now()

Die Quintessenz lautet: Alle in __init__.py Zugewiesenen Namen, seien es importierte Module, Funktionen oder Klassen, stehen automatisch im Paketnamensraum zur Verfügung, wenn Sie das Paket oder ein Modul im Paket importieren.

71

Es ist wirklich nur eine persönliche Vorliebe und hat mit dem Layout Ihrer python Module zu tun.

Angenommen, Sie haben ein Modul namens erikutils. Es gibt zwei Möglichkeiten, wie es ein Modul sein kann: Entweder haben Sie eine Datei mit dem Namen erikutils.py auf Ihrem sys.path oder Sie haben ein Verzeichnis mit dem Namen erikutils auf Ihrem sys.path mit einem leeren __init__.py Datei darin. Nehmen wir an, Sie haben eine Reihe von Modulen mit den Namen fileutils, procutils, parseutils und möchten, dass diese Submodule unter erikutils sind. Sie erstellen also einige .py-Dateien mit den Namen fileutils.py, procutils.py und parseutils.py:

erikutils
  __init__.py
  fileutils.py
  procutils.py
  parseutils.py

Vielleicht haben Sie einige Funktionen, die einfach nicht zu den Modulen fileutils, procutils oder parseutils gehören. Angenommen, Sie möchten kein neues Modul namens miscutils erstellen. UND, Sie möchten die Funktion folgendermaßen aufrufen können:

erikutils.foo()
erikutils.bar()

eher als zu tun

erikutils.miscutils.foo()
erikutils.miscutils.bar()

Da das erikutils -Modul ein Verzeichnis und keine Datei ist, müssen wir seine Funktionen im __init__.py Datei.

In Django ist das beste Beispiel, an das ich denken kann, Django.db.models.fields. ALLE Django * Feldklassen werden im __init__.py Datei im Verzeichnis Django/db/models/fields. Ich vermute, sie haben dies getan, weil sie nicht alles in ein hypothetisches Django/db/models/fields.py Modell packen wollten, also haben sie es in ein paar Submodule aufgeteilt (verwandt) .py, files.py, zum Beispiel) und sie haben die erstellten * Felddefinitionen im Feldmodul selbst abgelegt (daher __init__.py).

34
dgrant

Mit der Datei __init__.py Können Sie die interne Paketstruktur von außen unsichtbar machen. Wenn sich die interne Struktur ändert (z. B. weil Sie ein Fettmodul in zwei aufgeteilt haben), müssen Sie nur die Datei __init__.py Anpassen, nicht jedoch den Code, der vom Paket abhängt. Sie können auch Teile Ihres Pakets unsichtbar machen, z. wenn sie nicht für den allgemeinen Gebrauch bereit sind.

Beachten Sie, dass Sie den Befehl del verwenden können, sodass ein typischer __init__.py Wie folgt aussehen kann:

from somemodule import some_function1, some_function2, SomeObject

del somemodule

Wenn Sie sich nun entscheiden, somemodule aufzuteilen, könnte das neue __init__.py Sein:

from somemodule1 import some_function1, some_function2
from somemodule2 import SomeObject

del somemodule1
del somemodule2

Von außen sieht das Paket noch genauso aus wie bisher.

29
nikow