Wenn Sie Python verwenden, möchten Sie Ihre Dateien in einer Verzeichnishierarchie verwalten. Dort wird die Datei "__init __. Py" angezeigt.
Wer zur Hölle ist das? Es gibt viele Informationen, aber ich kann nichts finden, was sie auf sinnvolle Weise erklärt. Selbst in der Python-Dokumentation ist es schwierig zu wissen, worauf man sich für die richtige Antwort beziehen kann [^ Anmerkung 1].
[^ Anmerkung 1]: Es scheint, dass das Lesen von "Python Tutorial-Modules" die richtige Antwort ist (für die von Ihnen verwendete Version). Siehe die entsprechende Dokumentation. Als Tutorial, als ich es zum ersten Mal las, konnte ich es überhaupt nicht verstehen und sprang in mein Gedächtnis.
Also habe ich "__init __. Py" zusammengefasst. (Es ist ein bisschen lang)
Wenn Sie nur die Schlussfolgerung sehen möchten ("[ __init __. Py
role](# __ init__py- role) "), scrollen Sie zum letzten, da es in einem Leseformat geschrieben ist.
Das Python-Codebeispiel verwendet hauptsächlich 3.6 / 3.5 [^ Hinweis 2].
[^ Anmerkung 2]: Um das Rauschen zu reduzieren, werden Shebang wie "#! / Usr / bin / env python" und "- * - Codierung: utf-8 - * -" usw. der Zeichencode-Spezifikation ausgeschlossen. Und nur der Kernteil wird einfach beschrieben.
__init __. Py
](Rolle von # __init__py-)__all__
)Bevor Sie zum Hauptthema kommen, gehen Sie kurz auf "Module", "Pakete" und "Namespaces" ein.
[^ Anmerkung 3]: "Allgemeine Python-Terminologie" gibt "In Python neu codieren" an. Die zu verwendende Grundeinheit: Das heißt, ein Satz von Code, der aus anderem Code importiert wurde ".
Glossary: module An object that serves as an organizational unit of Python code. Modules have a namespace containing arbitrary Python objects. Modules are loaded into Python by the process of importing.
Siehe auch: "Python Documentation-Tutorial- Module"
[^ Anmerkung 4]: In "Python-Dokumentations-Tutorial- Pakete", "Module, die andere Module enthalten" "Es wurde beschrieben als.
Glossary: package A Python module which can contain submodules or recursively, subpackages. Technically, a package is a Python module with an __path__ attribute.
Glossary: namespace The place where a variable is stored. Namespaces are implemented as dictionaries. There are the local, global and built-in namespaces as well as nested namespaces in objects (in methods). Namespaces support modularity by preventing naming conflicts. For instance, the functions builtins.open and os.open() are distinguished by their namespaces. Namespaces also aid readability and maintainability by making it clear which module implements a function. For instance, writing random.seed() or itertools.islice() makes it clear that those functions are implemented by the random and itertools modules, respectively.
Namespace-Beispiel 1
import alpha.bravo.charlie
alpha.bravo.charlie.delta()
In diesem Beispiel (Beispiel 1) ist der Namespace eine hierarchische Struktur von "Alpha" → "Bravo" → "Charlie", und die Prozedur (Funktion) namens "Delta ()" ist in diesem "Charlie" implementiert. Ruft an.
Sie können intuitiv verstehen, dass wenn die oberen Namespaces unterschiedlich sind, auch wenn die unteren Namespaces denselben Namen haben, sie unterschiedliche Elemente sind.
Namespace-Beispiel 2
import os.path
os.path.join('/home', 'user')
Hier (Beispiel 2) ist ein häufig verwendetes Beispiel für das Verbinden von Pfaden, wobei "join ()" im Namespace "os" → "path" aufgerufen wird.
Bereiten Sie zwei Dateien im selben Verzeichnis vor.
Dateiorganisation
./
├─ module01.py .....Modul
└─ sample0010.py ...Ausführungsdatei(= Hauptmodul)
module01.py
: Definiert eine Funktion hello ()
, die nur "Hallo Welt!" Ausgibt.module1.py
def hello():
print( "Hello, world!" )
sample0010.py
: import
liest module01
und ruftmodule01.hello ()
auf.sample0010.py
import module01
module01.hello()
sample0010.Führen Sie py aus
$ python3 sample0010.py
Hello, world!
$ python2 sample0010.py
Hello, world!
Einzelne Dateimodule können "importiert" werden, indem sie im selben Verzeichnis abgelegt werden. Wenn Sie nur die Dateien trennen möchten, müssen Sie kein Verzeichnis erstellen.
Zu diesem Zeitpunkt ist "__init __. Py" nicht erforderlich.
Der Dateiname ist module01.py
, aber der Modulname ist module01
(Dateiname minus .py).
Der Namespace ist module01
.
Betrachten Sie das folgende Verzeichnis und die folgende Dateistruktur.
Probe 2 Hierarchische Struktur
./
├─ sample0020.py .....Ausführungsdatei
└─ dir/
└─ module02.py ...Modul
dir/module02.py
def hello():
print( "Hello, world! from module02" )
Zu diesem Zeitpunkt ist es zum Aufrufen von "module02" in "sample0020.py" erforderlich, wie folgt zu schreiben.
sample0020.py
import dir.module02
dir.module02.hello()
Ausführungsergebnis
$ python3 sample0020.py
Hello, world! from module02
$ python2 sample0020.py
Traceback (most recent call last):
File "sample0020.py", line 1, in <module>
import dir.module02
ImportError: No module named dir.module02
In Python3 hat es wie erwartet funktioniert, aber in Python2 ist ein Fehler aufgetreten. Dies liegt daran, dass wir "__init __. Py" unter "dir" benötigen.
Ab Version 3.3 kann es auch dann aufgerufen werden, wenn sich in dem Verzeichnis, in dem sich das aufrufende Modul befindet, kein "__init __. Py" befindet, aber im "normalen Paket" "__init __. Py" platziert werden soll.
What’s New In Python 3.3: PEP 420: Implicit Namespace Packages Native support for package directories that don’t require __init__.py marker files and can automatically span multiple path segments (inspired by various third party approaches to namespace packages, as described in PEP 420)
Dies ist eine Funktion für die neuen "Namespace-Pakete", die in Version 3.3 hinzugefügt wurden und für die "regulären Pakete" "__init __. Py" erfordern.
Regular packages A regular package is typically implemented as a directory containing an init.py file.
Sofern Sie keine "Namespace-Pakete" erstellen, müssen Sie "__init __. Py" in das Verzeichnis einfügen, in dem Sie die Module ablegen.
Schauen wir uns nun die Bedeutung von "__init __. Py" an.
In Beispiel 2 musste der Aufruf von "module02" im Namespace "dir.module02" referenziert werden, da es ein Verzeichnis mit dem Namen "dir /" gab.
dir
ist im Weg. Es hat keine Substanz, muss aber als Hierarchie von Namespaces angegeben werden.
Hier kommt __init __. Py
ins Spiel.
Die Methode zum direkten Aufrufen mit dem Namen "module02" nach dem Einfügen in die Verzeichnishierarchie lautet "__init __. Py".
Sie können das Verzeichnis "module02 /" anstelle von "dir /" benennen, aber die Datei, die Sie aufrufen, muss "module02" lauten. What .hello () ". Daher hat die Datei "__init __. Py" eine besondere Bedeutung, sodass sie als Modul mit demselben Namespace wie der Verzeichnisname behandelt werden kann.
Mit anderen Worten, indem Sie ein Programm in "module02 / __ init __. Py" anstelle von "dir / module02.py" schreiben, können Sie es als "module02" aufrufen.
Probe 3 __init__.Hierarchische Struktur einschließlich py
./
├─ sample0030.py .....Ausführungsdatei
└─ module02/
└─ __init__.py ... "module02"Entität von
module02/__init__.py
def hello():
print( "Hello, world! from __init__.py" )
sample0030.py
import module02
module02.hello()
Ausführungsergebnis
$ python2 sample0030.py
Hello, world! from __init__.py
$ python3 sample0030.py
Hello, world! from __init__.py
Ich kenne den historischen Hintergrund nicht (ich habe ihn nicht untersucht), aber ich vermute, dass dies das Original "__init __. Py" war. (Spekulation des Autors) Es gibt einen Platz zum Schreiben von init () in die Klasse (Namespace) des Moduls, das als Datei existiert, aber es gibt keinen Platz zum Schreiben von init () in den Namespace, der als Verzeichnis existiert. Es scheint, dass es aus dieser Datei namens "__init __. Py" besteht.
Und da "__init __. Py" die Existenz des Namespace darstellt, wäre "__init __. Py" als Markierung für das Modul verwendet worden. Daher bestand die Implementierung darin, dass das Verzeichnis, das die als Modul zu lesenden Dateien enthält, "__init __. Py" haben muss (= das Verzeichnis, das "__init __. Py" enthält, ist Teil des expliziten Namespace). Ich stelle es mir vor.
Wenn Sie "__init __. Py" eingeben, wird es als Entitätsmodul mit demselben Namespace wie der Verzeichnisname behandelt. Mit anderen Worten, "__init __. Py" ist eine Datei zum Zuordnen von Verzeichnisnamen als Modulnamen (oder explizite "Namespaces"). (Rolle des Konstruktors, wenn der Verzeichnisname als Namespace verwendet wird)
Wenn Sie dies verstehen können, werden Sie möglicherweise feststellen, dass "__init __. Py", das Sie bisher nicht verstanden haben, etwas vertrauter wird.
__init __. Py
Wenn Sie nach dem Verständnis der obigen Informationen "[Modul]" (https://docs.python.org/ja/3.6/tutorial/modules.html) des Python-Tutorials gelesen haben, lautet es "__init __. Py". Ich denke, die Rolle von ist leicht zu verstehen.
__init __. Py
initialisiert den Namespace, der nach dem Verzeichnis benannt ist, in dem er sich befindet.__init __. Py 'definiert auch das Ziel des Platzhalterimports im Namespace (Definition von
all`).2 . ~ 4 . Kann als "Initialisierung des Moduls oder Pakets" zusammengefasst werden, aber ich habe sie hier unterteilt.
__init __. py
wird als Markierung verwendet, um nach Modulen in der Hierarchie zu suchen.
"__Init __. Py" muss vorhanden sein, damit die verzeichnishierarchisierten Module geladen werden können.
(Wir werden keine "Namespace-Pakete" behandeln, für die kein "__init __. Py" erforderlich ist.)
Regular packages Python defines two types of packages, regular packages and namespace packages. Regular packages are traditional packages as they existed in Python 3.2 and earlier. A regular package is typically implemented as a directory containing an
__init__.py
file.
Wie wir bereits gesehen haben, registrieren Sie bei der Behandlung eines Verzeichnisnamens als Namespace-Modul den Inhalt, der zuerst ausgeführt werden soll, in "__init __. Py". Selbst wenn es sich um einen Import des unteren Moduls handelt, wird das untere Modul nach der Initialisierung ausgeführt, während der obere Namespace ausgeführt wird. Beachten Sie, dass eine Initialisierung vor dem Ausführen (Laden) des unteren Moduls erforderlich ist, bevor das untere Modul "importiert" wird.
__all__
)Obwohl es in "Python Tutorial- Import \ * from Package" beschrieben ist. Die Liste __all__
definiert, was beim Aufruf von my_module import *` importiert wird.
Dies ist nicht auf "__init __. Py" beschränkt, sondern kann in allen Modulen definiert werden.
Siehe Beispiel 4 unten. Haben Sie zwei Python-Skriptdateien im selben Verzeichnis.
Probe 4
./
├─ sample0040.py ...Ausführungsdatei
└─ module04.py .....Modul
sample0040.py
from module04 import *
hello1()
hello2()
hello3()
In sample0040.py
wird import
mit*
ausgeführt, z. B.from module04 import *
.
Es ist ein einfaches Programm, das "hello1 ()", "hello2 ()" und "hello3 ()" in der Reihenfolge nach "import" aufruft.
module04.py
__all__ = ['hello1', 'hello2']
def hello1():
print( "Hello, this is hello1" )
def hello2():
print( "Hello, this is hello2" )
def hello3():
print( "Hello, this is hello3" )
In "module04.py" sind "hello1 ()", "hello2 ()" und "hello3 ()" definiert. Die Liste "all" enthält nur "Hallo1" und "Hallo2", nicht "Hallo3".
Das Ausführungsergebnis ist wie folgt.
Ausführungsergebnis
$ python sample0040.py
Hello, this is hello1
Hello, this is hello2
Traceback (most recent call last):
File "sample0040.py", line 5, in <module>
hello3()
NameError: name 'hello3' is not defined
Der Aufruf von "hello3 ()" war undefiniert und führte zu dem Fehler "NameError: name'hello3 'ist nicht definiert". Dies liegt daran, dass es nicht in der Liste von "all" enthalten ist. Dies bedeutet nicht, dass "hello3 ()" versteckt ist, sondern nur das Verhalten, wenn "import " verwendet wird. Als Test können Sie auch "hello3 ()" per "import" aufrufen, ohne "" zu verwenden und "module04" explizit aufzurufen.
sample0041.py
import module04
module04.hello1()
module04.hello2()
module04.hello3()
Ausführungsergebnis
$ python sample0041.py
Hello, this is hello1
Hello, this is hello2
Hello, this is hello3
Das Definieren von "all" in "__init __. Py" definiert nur ein Objekt, auf das verwiesen werden kann, wenn ein Modul, dessen Namespace ein Verzeichnisname ist, mit "*" "importiert" wird.
Ich habe oben geschrieben, dass Sie es als Modul mit demselben Namen wie den Verzeichnisnamen aufrufen können, indem Sie eine Funktion usw. in `__init __. Py 'definieren. Wenn "__init __. Py" größer wird, sollten Sie nur die Initialisierung in "__init __. Py" schreiben und die Datei fernhalten.
Versuchen Sie es mit dem folgenden Verzeichnis und der folgenden Dateistruktur.
Probe 5
./
├─ sample0050.py ......Ausführungsdatei
└─ module05
├─ __init__.py .... "module05"Initialisierungsdatei
├─ _module05.py ... "module05"Entität von
└─ module06.py .... "module05"Zusätzliche Module
Es wird angenommen, dass "module05 / _module05.py" von Anfang an als "module05" bereitgestellt wurde, oder es wurde herausgenommen, weil "__init __. Py" geschwollen war.
Ich habe einen Unterstrich (_
) hinzugefügt, um den gleichen Dateinamen wie das Verzeichnis zu erhalten, damit er als tatsächlicher Modulname angezeigt werden kann.
python:./module05/_module05.py
print( "in _module05.py" )
def hello(caller=""):
print( "Hello, world! in _module05 called by {}".format(caller) )
Es wird angenommen, dass module05 / module06.py
eine Datei ist, die von Anfang an außerhalb von __init __. Py entwickelt wurde.
python:./module05/module06.py
print( "in module06.py" )
def hello(caller=""):
print( "Hello, world! in module06 called by {}".format(caller) )
Sowohl hello ()
in _module05.py
als auch hello ()
in module06.py
übergeben einen Aufrufer als Argument, damit der Aufrufer es weiß.
Übrigens liest "__init __. Py" Module im selben Verzeichnis, daher wird "_module05 "und" module06 "ein Punkt (". ") Vorangestellt, der das aktuelle Verzeichnis (denselben Namespace) darstellt. Da die Namen von "hello ()" in Konflikt stehen, benennen wir sie mit "as" um.
python:./module05/__init__.py
print( "in __init__.py" )
# import _module05.hello() as hello05() in the same directory
from ._module05 import hello as hello05
# import module06.hello() as hello06() in the same directory
from .module06 import hello as hello06
__all__ = ['hello05', 'hello06']
# Do initialize something bellow
hello05("__init__.py")
hello06("__init__.py")
Unter der Definition des Objekts, das von "all" als "*" bezeichnet werden kann, wird angenommen, dass eine Initialisierung durchgeführt wird.
Der ursprüngliche Aufruf "sample0050.py" lautet wie folgt.
Mit from module05 import *
wird nur das Modul von module05
geladen.
python:./sample0050.py
print( "in {} 1".format( __file__ ) )
from module05 import *
print( "in {} 2".format( __file__ ) )
hello05(__file__)
hello06(__file__)
Das Ausführungsergebnis ist wie folgt.
Ausführungsergebnis
$ python3 sample0050.py
in sample0050.py 1
in __init__.py
in _module05.py
in module06.py
Hello, world! in _module05 called by __init__.py
Hello, world! in module06 called by __init__.py
in sample0050.py 2
Hello, world! in _module05 called by sample0050.py
Hello, world! in module06 called by sample0050.py
Sie können sehen, dass module05 / _module05.py
und module05 / module06.py
durch Eingreifen von__init __. Py" als
module05` bezeichnet werden.
Übrigens ist module05 / module06.py
nicht versteckt, so dass Sie es direkt aufrufen können.
module05/module06.Direkter Anruf bei py
$ python3 -c "import module05.module06; module05.module06.hello('shell')"
in __init__.py
in _module05.py
in module06.py
Hello, world! in _module05 called by __init__.py
Hello, world! in module06 called by __init__.py
Hello, world! in module06 called by shell
Sobald Sie dies verstanden haben, werden Sie wahrscheinlich Module entwickeln können, die als "Pakete" wiederverwendet werden können.
Ich habe die Rolle von "__init __. Py" bei der Überprüfung bestätigt.
Es wird oft geschrieben, dass es eine Rolle gibt, aber hier wird die zweite Rolle in drei Teilen beschrieben.
2-1. Initialisierung des Namespace 2-2. Definition des Ziels des Platzhalters "Import" (Definition von "all") 2-3. Definition von Namespaces für andere Module im selben Verzeichnis
Drittens ist es möglich, andere Module, die sich nicht im selben Verzeichnis befinden, durch "Importieren" zu definieren, aber zunächst ist es ein Modul, das sich im selben Verzeichnis befindet.
In Bezug auf die im Modul beschriebenen Ausführungsanweisungen wird angegeben, dass "diese Ausführungsanweisungen nur ausgeführt werden, wenn der Modulname zum ersten Mal in der Importanweisung gefunden wird" [^ Hinweis 5], Egal wie oft Sie "Import" wiederholen, es wird nur einmal ausgeführt. (Wenn Sie "importlib" für "importlib.reload ()" verwenden, wird dies explizit ausgeführt.)
Nach dem Lesen dieses Beitrags denke ich, dass Sie ein besseres Verständnis erhalten, wenn Sie "Python Tutorial-Module" erneut lesen. Ich werde.
Ich hoffe es hilft dir sogar ein wenig.
Hinzugefügt von Kommentar von @methane (2020/01/20)
__init __. py
fungiert als Marker und wird von unittest verwendet, um nach Testmodulen unterhalb der Hierarchie zu suchen, insbesondere in unserer unmittelbaren Umgebung.
Ein Beispiel ist unten gezeigt.
unittest Testumgebungsbaum
./
├─ my_module
│ ├─ __init__.py ............. my_Für die Modulzuordnung
| └─ _my_module.py ........... my_Die Substanz des Moduls
|
├─ tests-without__init__/ ...... __init__.Testverzeichnis ohne py
| └─ unit/ ...................Hierarchie für Unit-Test
| └─ test_my_module.py ...Testprogramm
|
└─ tests-with__init__/ ......... __init__.Testverzeichnis mit py
└─ unit/ ...................Hierarchie für Unit-Test
├─ __init__.py .........Legen Sie einfach die Datei. Der Inhalt ist leer.
└─ test_my_module.py ... tests-without/unit/test_my_module.Symbolischer Link zu py
Installieren Sie "my_module / __ init __. Py" und "my_module / _my_module.py", um "my_module" vorzubereiten.
python:my_module/__init__.py - my_Als Modul_my_module.Laden Sie py
__all__ = [
'Sample',
]
from ._my_module import Sample
my_module/_my_module.py - my_Definieren Sie den Inhalt des Moduls
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import six
class Sample:
def __init__(self):
self.message = "__file__: " + __file__ + ", __name__:" + __name__
self.saved_message = self.message
def get(self): #Dieses Testziel
return self.message
if __name__ == "__main__":
sample = Sample()
six.print_( sample.get() )
Bereiten Sie test_my_module.py
unter der Hierarchie vor, um mit unittest zu testen.
Setzen Sie "__init . Py" nicht unter "tests-without__init / unit /".
tests-without__init__/unit/test_my_module.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os
import unittest
#Umgebungsvariable MY_MODULE_Lesen Sie PATH, sys.Auf Pfad setzen
module_dir = os.getenv( 'MY_MODULE_PATH', default=os.getcwd() )
sys.path.append( module_dir )
from my_module import Sample
class myClass(unittest.TestCase):
global module_dir
def setUp(self):
self.moduledir = os.path.join( module_dir, "my_module" )
self.modulefilepath = os.path.join( self.moduledir, "_my_module.py" )
self.modulename = "my_module._my_module"
self.sample = Sample()
def tearDown(self):
del self.sample
# Sample.get()Test von
def test_get(self):
self.assertEqual( self.sample.get(), "__file__: " + self.modulefilepath + ", __name__:" + self.modulename )
if __name__ == "__main__":
unittest.main()
Bereiten Sie test_my_module.py
unter der Hierarchie vor, um mit unittest zu testen.
(Eigentlich ist es eine symbolische Verknüpfung, genau wie der Inhalt von tests-without__init__ / unit / test_my_module.py
)
Platzieren Sie eine leere Datei __init __. Py
unter tests-with__init__ / unit /
.
tests-with__init__/unit/__init__.py
# nothing here
tests-with__init__/unit/test_my_module.py
tests-without__init__/unit/test_my_module.Gleicher Inhalt wie py(Symbolischer Link)
Führen Sie den Test aus. Zuallererst von der Person, die "__init __. Py" hat.
__init__.Ausführungsergebnis mit py
$ python3 -m unittest discover tests-with__init__/ -v
test_get (unit.test_my_module.myClass) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
$
Es heißt "Ran 1 Test", ich habe das Testprogramm unter "unit /" gefunden und es ausgeführt.
Auf der anderen Seite, wenn "__init __. Py" nicht existiert ...
__init__.Ausführungsergebnis ohne py
$ python3 -m unittest discover tests-without__init__/ -v
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
$
Ohne __init __. Py 'wird das Testprogramm unter
unit /` nicht gefunden und der Test wird nicht ausgeführt.
Recommended Posts