Wofür ist __init__.py?

Antworten:

1454

Früher war es ein erforderlicher Teil eines Pakets ( altes "reguläres Paket" vor 3.3 , nicht neueres 3.3+ "Namespace-Paket"). ).

Hier ist die Dokumentation.

Python definiert zwei Arten von Paketen, reguläre Pakete und Namespace-Pakete. Normale Pakete sind traditionelle Pakete, wie sie in Python 3.2 und früheren Versionen vorhanden waren. Ein reguläres Paket wird normalerweise als Verzeichnis implementiert, das eine __init__.pyDatei enthält. Wenn ein reguläres Paket importiert wird, wird diese __init__.pyDatei implizit ausgeführt, und die von ihr definierten Objekte werden an Namen im Namespace des Pakets gebunden. Die __init__.pyDatei kann denselben Python-Code enthalten, den jedes andere Modul enthalten kann, und Python fügt dem Modul beim Import einige zusätzliche Attribute hinzu.

Klicken Sie einfach auf den Link. Er enthält ein Beispiel, weitere Informationen und eine Erläuterung der Namespace-Pakete, der Art von Paketen ohne __init__.py.

Loki
quelle
187
Was bedeutet dies: "Dies geschieht, um zu verhindern, dass Verzeichnisse mit einem allgemeinen Namen, wie z. B. eine Zeichenfolge, unbeabsichtigt gültige Module verbergen, die später im Modul-Suchpfad auftreten."
Carl G
97
@CarlG Python durchsucht eine Liste von Verzeichnissen , um Namen in z. B. Importanweisungen aufzulösen. Da es sich um ein beliebiges Verzeichnis handeln kann und vom Endbenutzer beliebige hinzugefügt werden können, müssen sich die Entwickler um Verzeichnisse kümmern, die zufällig einen Namen mit einem gültigen Python-Modul teilen, z. B. 'string' im Beispiel docs. Um dies zu vermeiden, werden Verzeichnisse ignoriert, die keine Datei mit dem Namen _ _ init _ _.py (keine Leerzeichen) enthalten, auch wenn sie leer ist.
Zwei-Bit-Alchemist
186
@CarlG Versuchen Sie dies. Erstellen Sie ein Verzeichnis mit dem Namen 'datetime' und erstellen Sie darin zwei leere Dateien, die Datei init.py (mit Unterstrichen) und datetime.py. Öffnen Sie nun einen Interpreter, importieren Sie sys und geben Sie ihn aus sys.path.insert(0, '/path/to/datetime')und ersetzen Sie diesen Pfad durch den Pfad zu dem gerade erstellten Verzeichnis. Versuchen Sie jetzt so etwas from datetime import datetime;datetime.now(). Sie sollten einen AttributeError erhalten (da jetzt Ihre leere Datei importiert wird). Wenn Sie diese Schritte wiederholen würden, ohne die leere Init-Datei zu erstellen, würde dies nicht passieren. Das soll verhindert werden.
Zwei-Bit-Alchemist
4
@ DarekNędza Sie haben etwas falsch eingerichtet, wenn Sie nicht einfach einen Python-Interpreter öffnen und from datetime import datetimeohne Fehler ausgeben können. Das ist gut bis zur Version 2.3!
Zwei-Bit-Alchemist
5
@SWang: Das ist falsch: builtinslistet integrierte Funktionen und Klassen auf , keine integrierten Module (vgl. Docs.python.org/3/tutorial/modules.html#the-dir-function ). Wenn Sie integrierte Module auflisten möchten , tun Sie dies import sys; print(sys.builtin_module_names)(vgl. Docs.python.org/3/library/sys.html#sys.builtin_module_names ).
Maggyero
842

Die genannten Dateien __init__.pywerden verwendet, um Verzeichnisse auf der Festplatte als Python-Paketverzeichnisse zu markieren. Wenn Sie die Dateien haben

mydir/spam/__init__.py
mydir/spam/module.py

und mydirist auf Ihrem Weg, können Sie den Code in module.pyas importieren

import spam.module

oder

from spam import module

Wenn Sie die entfernen __init__.py Datei , sucht Python nicht mehr nach Submodulen in diesem Verzeichnis, sodass Versuche, das Modul zu importieren, fehlschlagen.

Die __init__.pyDatei ist normalerweise leer, kann jedoch verwendet werden, um ausgewählte Teile des Pakets unter einem bequemeren Namen zu exportieren, Komfortfunktionen zu speichern usw. Im obigen Beispiel kann auf den Inhalt des Init-Moduls zugegriffen werden als

import spam

basierend darauf

Caritos
quelle
96
Update: Die Datei __init__.pywar unter Python 2.X erforderlich und wird weiterhin unter Python 2.7.12 benötigt (ich habe sie getestet), wird jedoch ab (angeblich) Python 3.3 nicht mehr benötigt und ist unter Python 3.4.3 (I) nicht mehr erforderlich getestet). Weitere Informationen finden Sie unter stackoverflow.com/questions/37139786 .
Rob_before_edits
4
Benutze es nicht. Es ist ein "Namespace" -Paket, kein reguläres Paket. Das Namespace-Paket wird für sehr seltene Anwendungsfälle verwendet. Möglicherweise müssen Sie nicht wissen, wann Sie es verwenden. Einfach benutzen __init__.py.
Methan
2
Wenn Sie jedoch haben setup.pyund verwenden find_packages(), ist es notwendig, __init__.pyin jedem Verzeichnis zu haben . Siehe stackoverflow.com/a/56277323/7127824
techkuz
484

Zusätzlich ein Verzeichnis als Python - Paket Beschriftung und definieren __all__, __init__.pykönnen Sie eine beliebige Variable auf Paketebene definieren.Dies ist häufig praktisch, wenn ein Paket etwas definiert, das häufig auf API-ähnliche Weise importiert wird. Dieses Muster fördert die Einhaltung der pythonischen Philosophie "Wohnung ist besser als verschachtelt".

Ein Beispiel

Hier ist ein Beispiel aus einem meiner Projekte, in das ich häufig einen sessionmakerAufruf importiere , Sessionum mit meiner Datenbank zu interagieren. Ich habe ein "Datenbank" -Paket mit einigen Modulen geschrieben:

database/
    __init__.py
    schema.py
    insertions.py
    queries.py

Mein __init__.pyenthält den folgenden Code:

import os

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)

Da ich Sessionhier definiere , kann ich eine neue Sitzung mit der folgenden Syntax starten. Dieser Code wird von innerhalb oder außerhalb des Paketverzeichnisses "Datenbank" ausgeführt.

from database import Session
session = Session()

Dies ist natürlich eine kleine Annehmlichkeit - die Alternative wäre, Sessionin einer neuen Datei wie "create_session.py" in meinem Datenbankpaket zu definieren und neue Sitzungen zu starten, indem Sie:

from database.create_session import Session
session = Session()

Weiterführende Literatur

Es gibt einen ziemlich interessanten reddit-Thread, der die entsprechenden Verwendungszwecke von __init__.pyhier abdeckt :

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

Die Mehrheitsmeinung scheint zu sein, dass __init__.pyDateien sehr dünn sein sollten, um einen Verstoß gegen die Philosophie "explizit ist besser als implizit" zu vermeiden.

Nathan Gould
quelle
3
engine, sessionmaker, create_engine, Und osalle auch importiert werden kann databasejetzt ... scheint , wie Sie ein Durcheinander von diesem Namensraum vorgenommen haben.
ArtOfWarfare
9
@ArtOfWarfare können Sie verwenden, um __all__ = [...]zu begrenzen, mit was importiert wird import *. Abgesehen davon bleibt Ihnen ein unordentlicher Namespace der obersten Ebene.
Nathan Gould
Darf ich wissen, wie lautet die 'DATABASE URL'? Ich habe versucht, dies zu replizieren, indem ich die create_engine mit 'mysql + mysqldb: // root: python @ localhost: 3306 / test' eingeschlossen habe, aber es funktioniert nicht. Vielen Dank.
SunnyBoiz
2
Wie würden Sie von innerhalb des Pakets, z. B. quieries.py , auf die in init definierte ' Session' -Klasse zugreifen?
Vldbnc
252

Es gibt 2 Hauptgründe für __init__.py

  1. Der Einfachheit halber: Die anderen Benutzer müssen den genauen Speicherort Ihrer Funktionen in Ihrer Pakethierarchie nicht kennen.

    your_package/
      __init__.py
      file1.py
      file2.py
        ...
      fileN.py
    # in __init__.py
    from file1 import *
    from file2 import *
    ...
    from fileN import *
    # in file1.py
    def add():
        pass

    dann können andere add () von aufrufen

    from your_package import add

    ohne file1 zu kennen, wie

    from your_package.file1 import add
  2. Wenn Sie möchten, dass etwas initialisiert wird; Zum Beispiel Protokollierung (die in die oberste Ebene gestellt werden sollte):

    import logging.config
    logging.config.dictConfig(Your_logging_config)
Flycee
quelle
7
Oh, bevor ich Ihre Antwort gelesen habe, dachte ich, dass es eine gute Praxis ist, eine Funktion explizit von ihrem Standort aus aufzurufen.
Aerin
2
@Aerin es wäre besser, kurze Aussagen (oder in diesem Fall subjektive Schlussfolgerungen) nicht immer als wahr zu betrachten. Das Importieren von __init__.pykann manchmal nützlich sein, aber nicht immer.
Tobias Sette
2
Werden diese Codes zur Import- oder Laufzeit ausgeführt?
user1559897
111

Die __init__.pyDatei lässt Python Verzeichnisse, die sie enthalten, als Module behandeln.

Darüber hinaus ist dies die erste Datei, die in ein Modul geladen wird, sodass Sie damit Code ausführen können, den Sie bei jedem Laden eines Moduls ausführen möchten, oder die zu exportierenden Submodule angeben können.

Kann Berk Güder
quelle
89

Seit Python 3.3 __init__.py ist es nicht mehr erforderlich, Verzeichnisse als importierbare Python-Pakete zu definieren.

Überprüfen Sie PEP 420: Implizite Namespace-Pakete :

Native Unterstützung für Paketverzeichnisse, für die keine __init__.pyMarkierungsdateien erforderlich sind und die sich automatisch über mehrere Pfadsegmente erstrecken können (inspiriert von verschiedenen Ansätzen von Drittanbietern für Namespace-Pakete, wie in PEP 420 beschrieben ).

Hier ist der Test:

$ 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

Referenzen:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
Is __init__. py nicht erforderlich für Pakete in Python 3?

zeekvfu
quelle
3
Es ist ein "Namespace" -Paket. Verwenden Sie es nicht für normale Pakete.
Methan
@methan, könntest du deinen Kommentar näher erläutern?
Robert Lugg
3
@ RobertLugg Siehe dev.to/methane/don-t-omit-init-py-3hga
Methan
57

In Python ist die Definition des Pakets sehr einfach. Wie bei Java sind die hierarchische Struktur und die Verzeichnisstruktur gleich. Aber Sie müssen __init__.pyin einem Paket haben. Ich werde die __init__.pyDatei mit dem folgenden Beispiel erklären :

package_x/
|--  __init__.py
|--    subPackage_a/
|------  __init__.py
|------  module_m1.py
|--    subPackage_b/
|------  __init__.py
|------  module_n1.py
|------  module_n2.py
|------  module_n3.py

__init__.pykann leer sein, solange es existiert. Es gibt an, dass das Verzeichnis als Paket betrachtet werden sollte. Natürlich __init__.pykann auch der entsprechende Inhalt eingestellt werden.

Wenn wir eine Funktion in module_n1 hinzufügen:

def function_X():
    print "function_X in module_n1"
    return

Nach dem Rennen:

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

function_X in module_n1 

Dann folgten wir dem Hierarchiepaket und nannten die Funktion module_n1. Wir können __init__.pyin subPackage_b Folgendes verwenden:

__all__ = ['module_n2', 'module_n3']

Nach dem Rennen:

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

Bei Verwendung des * Imports unterliegt das Modulpaket daher dem __init__.pyInhalt.

Marcus Thornton
quelle
Wie sieht meine setup.py aus, um denselben Import über die gepackte Bibliothek durchzuführen? from package_x.subPackage_b.module_n1 import function_X
Technazi
Der Schlüssel zum Mitnehmen lautet also "Verwenden von * Importieren, Modulpaket unterliegt dem Inhalt von init .py"
Minnie
54

Obwohl Python ohne __init__.pyDatei funktioniert , sollten Sie dennoch eine einschließen.

Es gibt an, dass ein Paket als Modul behandelt werden soll. Fügen Sie es daher hinzu (auch wenn es leer ist).

Es gibt auch einen Fall, in dem Sie tatsächlich eine __init__.pyDatei verwenden können:

Stellen Sie sich vor, Sie hätten die folgende Dateistruktur:

main_methods 
    |- methods.py

Und methods.pyenthielt dies:

def foo():
    return 'foo'

Zur Verwendung foo()benötigen Sie eine der folgenden Möglichkeiten :

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

Vielleicht müssen (oder möchten) Sie dort methods.pydrinnen bleiben main_methods(z. B. Laufzeiten / Abhängigkeiten), aber Sie möchten nur importieren main_methods.


Wenn Sie den Namen von methods.pyin geändert haben , können __init__.pySie foo()Folgendes verwenden main_methods:

import main_methods
print(main_methods.foo()) # Prints 'foo'

Dies funktioniert, weil __init__.pyes als Teil des Pakets behandelt wird.


Einige Python-Pakete tun dies tatsächlich. Ein Beispiel ist JSON , bei dem das Ausführen import jsontatsächlich __init__.pyaus dem jsonPaket importiert wird ( siehe die Struktur der Paketdatei hier ):

Quellcode: Lib/json/__init__.py

Simon
quelle
39

__init__.py behandelt das Verzeichnis, in dem es sich befindet, als ladbares Modul.

Für Leute, die lieber Code lesen, habe ich hier den Kommentar von Two-Bit Alchemist eingefügt.

$ 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
>>> 
B.Mr.W.
quelle
30

Es erleichtert das Importieren anderer Python-Dateien. Wenn Sie diese Datei in einem Verzeichnis (z. B. Sachen) abgelegt haben, das andere py-Dateien enthält, können Sie so etwas wie import stuff.other ausführen.

root\
    stuff\
         other.py

    morestuff\
         another.py

Ohne dies __init__.pyim Verzeichnis stuff könnten Sie other.py nicht importieren, da Python nicht weiß, wo sich der Quellcode für stuff befindet, und es nicht als Paket erkennen kann.

Epitaph
quelle
2
Ich habe die gleiche Struktur in meinem Projekt (Python 3.4), aber ich bin nicht in der Lage, eine andere.py zu machen, andere.py zu sehen. Wie soll ich den Import machen? aus root.stuff andere importieren? Es funktioniert im VSCode-Debug-Modus, jedoch nicht in der Befehlszeile. Irgendwelche Ideen?
Rodrigorf
10

Eine __init__.pyDatei erleichtert den Import. Wenn eine __init__.pyin einem Paket vorhanden ist, a()kann die Funktion b.pywie folgt aus einer Datei importiert werden:

from b import a

Ohne sie können Sie jedoch nicht direkt importieren. Sie müssen den Systempfad ändern:

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

from b import a
Alec Alameddine
quelle
Was meinst du mit " Funktion a () kann aus der Datei b.py [Snippet] importiert werden ? Ohne sie können Sie jedoch nicht direkt importieren. "? Ich kann die Funktion a () aus der Datei b.py ohne __init__.py importieren.
Aderchox