2008-09-23 12 views
75

Ich nehme einmal an, wie das Modellsystem in django arbeitet, und ich bemerkte etwas, das ich nicht verstehe.Hinzufügen von Code __init__.py

Ich weiß, dass Sie eine leere __init__.py Datei erstellen, dass das aktuelle Verzeichnis ist ein Paket. Und dass Sie eine Variable in __init__.py setzen können, damit der Import * ordnungsgemäß funktioniert.

Aber Django fügt eine Menge von ... Import ... Anweisungen hinzu und definiert eine Reihe von Klassen in __init__.py. Warum? Macht das die Dinge nicht nur unordentlich? Gibt es einen Grund, der diesen Code in __init__.py erfordert?

+13

Dies ist nicht wirklich über Django ist es? Ja, du hast es zuerst in Django gesehen, aber das scheint eher eine reine Python-Sache zu sein - vielleicht ist das Django-Tag nicht wirklich passend. –

+0

Ich sehe keine Importanweisungen in '__init __. Py' django 1.8. War das für eine ältere Version? wenn ja welche Version? –

Antwort

67

alle Einfuhren in __init__.py zur Verfügung gestellt werden, wenn Sie das Paket (Verzeichnis) importieren, die es enthält.

Beispiel:

./dir/__init__.py:

import something 

./test.py:

import dir 
# can now use dir.something 

EDIT: vergessen Sie den Code in __init__.py zu erwähnen, läuft das erste Mal, wenn Sie aus diesem Verzeichnis ein beliebiges Modul importieren. Daher ist es normalerweise ein guter Ort, um einen Initialisierungscode auf Paketebene zu setzen.

EDIT2: dgrant wies darauf hin, auf eine mögliche Verwirrung in meinem Beispiel. In __init__.pyimport something kann jedes Modul importieren, nicht notwendig aus dem Paket. Zum Beispiel können wir es mit import datetime, dann in unserem Top-Level-test.py beide dieser Schnipsel ersetzen funktioniert:

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

und

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

Unterm Strich: alle in __init__.py zugewiesenen Namen, sein Es importiert Module, Funktionen oder Klassen und ist automatisch im Paket-Namespace verfügbar, wenn Sie das Paket oder ein Modul in das Paket importieren.

+0

Okay, danke. Aber ich bin mir immer noch nicht sicher, warum es eine gute Idee wäre, Klassen zu '__init __. Py' hinzuzufügen. Ich betrachte diese Klassen nicht wirklich als Initialisierungscode (aber vielleicht irre ich mich damit). – Erik

+0

Dies sind wahrscheinlich die Klassen, die bei jeder Arbeit mit dem Paket nützlich sind. Aber ich möchte nicht spekulieren, es könnte viele Gründe geben, warum sie da sind, objektiv oder nicht :) –

+12

Das kann auch aus historischen Gründen sein. Wenn Sie ein Modul in ein Paket konvertieren, module.py in ein Modul/__ init__.py, kann der gesamte vorhandene Code es wie zuvor verwenden, aber das Modul kann jetzt Submodule haben. –

32

Es ist nur persönliche Präferenz wirklich, und hat mit dem Layout Ihrer Python-Modulen zu tun.

Angenommen, Sie haben ein Modul erikutils genannt haben. Es gibt zwei Möglichkeiten, dass es ein Modul sein kann, haben Sie entweder eine Datei erikutils.py auf Ihrem sys.path genannt, oder Sie haben ein Verzeichnis erikutils auf sys.path mit einer leeren __init__.py Datei in es nennt. Dann lassen Sie uns sagen, dass Sie eine Reihe von Modulen namens fileutils, procutils, parseutils und Sie wollen, dass die Submodule unter erikutils sein. So machen Sie einige Py Dateien namens fileutils.py, procutils.py und parseutils.py:

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

Vielleicht haben Sie einige Funktionen, die nur gehören nicht in den fileutils, procutils oder parseutils Module.Nehmen wir an, Sie möchten kein neues Modul namens miscutils erstellen. AND, Sie möchten in der Lage sein, um die Funktion aufzurufen, wie so:

erikutils.foo() 
erikutils.bar() 

anstatt tun

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

So, da das erikutils Modul ist ein Verzeichnis, keine Datei, müssen wir definieren es funktioniert innerhalb der __init__.py Datei.

In Django, das beste Beispiel, das ich denken kann, ist django.db.models.fields. Alle django * -Feldklassen sind in der __init__.py Datei im Verzeichnis django/db/models/fields definiert. Ich nehme an, sie taten das, weil sie nicht alles in ein hypothetisches Modell stopfen wollten, also verteilten sie es in ein paar Submodule (verwandte.py, files.py, zum Beispiel) und sie stecken die gemachten * Felddefinitionen in die Felder Modul selbst (daher __init__.py).

+1

dgrant, was ich meinte ist, dass 'etwas' ein externes Modul sein kann, das wird etwas funktionieren.Danke für den Kommentar, ich werde meinen Beitrag bearbeiten, um es klarer zu machen. –

+0

Großartig, danke dgrant. – Erik

26

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 fettes Modul in zwei teilen), müssen Sie nur die Datei __init__.py anpassen, aber nicht den Code, der vom Paket abhängt. Sie können Teile Ihres Pakets auch unsichtbar machen, z. wenn sie nicht für den allgemeinen Gebrauch bereit sind.

Beachten Sie, dass Sie den del Befehl verwenden können, so ein typisches __init__.py wie folgt aussehen:

from somemodule import some_function1, some_function2, SomeObject 

del somemodule 

Nun, wenn Sie sich entschließen, zu spalten somemodule die neue __init__.py könnte sein:

from somemodule1 import some_function1, some_function2 
from somemodule2 import SomeObject 

del somemodule1 
del somemodule2 

Aus Das Äußere des Pakets sieht immer noch genauso aus wie zuvor.

+1

Was ist der Sinn des Löschens eines Moduls? – Arlen

+0

@Arlen: Der Punkt ist, dass es nicht Teil der öffentlichen API ist. Wenn Sie ein Modul umbenennen, können Sie sicher sein, dass kein abhängiger Code bricht. Darüber hinaus wird dadurch sichergestellt, dass die API-Elemente nur einmal angezeigt werden, z. B. wenn Introspektion verwendet wird, um automatisch API-Dokumentation zu erstellen. – nikow

+4

@Arlen: Das Löschen eines Moduls verhindert, dass man " .somemodule1" direkt importiert. Sie können nur von '' Objekten importieren, die in ihrem' _init___py' definiert und importiert wurden, und nicht gelöschte Submodule. – MestreLion