Przyglądam się, jak działa system modelowy w django i zauważyłem coś, czego nie rozumiem.
Wiem, że tworzysz pusty __init__.py
plik, aby określić, że bieżący katalog jest pakietem. I że możesz ustawić jakąś zmienną w programie __init__.py
, aby import * działał poprawnie.
Ale django dodaje kilka instrukcji from ... import ... i definiuje kilka klas w __init__.py
. Czemu? Czy to nie sprawia, że wszystko wygląda na bałagan? Czy istnieje powód, dla którego ten kod jest wymagany __init__.py
?
__init__.py
django 1.8. Czy to dotyczyło starszej wersji? jeśli tak, która wersja?Odpowiedzi:
Wszystkie importy w programie
__init__.py
są dostępne podczas importowania pakietu (katalogu), który go zawiera.Przykład:
./dir/__init__.py
:import something
./test.py
:import dir # can now use dir.something
EDYCJA: zapomniałem wspomnieć, że kod jest
__init__.py
uruchamiany przy pierwszym imporcie modułu z tego katalogu. Zwykle jest to więc dobre miejsce na umieszczenie dowolnego kodu inicjującego na poziomie pakietu.EDIT2: dgrant wskazał na możliwe zamieszanie w moim przykładzie. W
__init__.py
import something
może importować każdego modułu, nie jest konieczne z opakowania. Na przykład możemy go zamienić naimport datetime
, wtedy na naszym najwyższym poziomietest.py
oba te fragmenty będą działać:import dir print dir.datetime.datetime.now()
i
import dir.some_module_in_dir print dir.datetime.datetime.now()
Najważniejsze jest to, że wszystkie nazwy przypisane w
__init__.py
, czy to zaimportowanych modułach, funkcjach czy klasach, są automatycznie dostępne w przestrzeni nazw pakietu za każdym razem, gdy importujesz pakiet lub moduł w pakiecie.źródło
__init__.py
Tak naprawdę nie biorę pod uwagę kodu inicjalizacji tych klas (ale może się mylę).__init__.py
niejawnie. Importując moduły do środka__init__.py
, tworzysz cykliczne importy.__init__.py
Nie zostanie wykonany w pełni przed jednym takim imporcie. Bezpieczniej jest trzymać__init__.py
puste.__init__.py
plików. Gdybyś miał plik,dir/other.py
który zawierał coś takiego,from datetime import datetime
mógłbyś również zadzwonićdir.other.datetime.now()
lub nawetfrom dir.other import datetime
.To tylko osobiste preferencje i ma związek z układem modułów w Pythonie.
Powiedzmy, że masz moduł o nazwie
erikutils
. Istnieją dwa sposoby, że może to być moduł, albo masz plik o nazwie erikutils.py na własnąsys.path
lub masz katalog o nazwie erikutils na własnąsys.path
pustym__init__.py
pliku wewnątrz niego. Pozwól, że masz kilka modułów zwanychfileutils
,procutils
,parseutils
i chcesz te podwykonawstwa w ramach modułów mocyerikutils
. Więc tworzysz kilka plików .py o nazwach fileutils.py , procutils.py i parseutils.py :Może masz kilka funkcji, które po prostu nie należą w
fileutils
,procutils
lubparseutils
modułów. Powiedzmy, że nie masz ochoty tworzyć nowego modułu o nazwiemiscutils
. ORAZ chciałbyś móc wywołać funkcję w ten sposób:zamiast robić
Więc ponieważ
erikutils
moduł jest katalogiem, a nie plikiem, musimy zdefiniować jego funkcje wewnątrz__init__.py
pliku.W django najlepszym przykładem, jaki przychodzi mi do głowy, jest
django.db.models.fields
. WSZYSTKIE klasy django * Field są zdefiniowane w__init__.py
pliku w katalogu django / db / models / fields . Myślę, że zrobił to dlatego, że nie chce się dopchać wszystko do hipotetycznego django / db / models / fields.py modelu, więc podzielić ją na kilka submodułów ( related.py , files.py , na przykład) i utknęli utworzone * definicje pól w samym module pól (stąd,__init__.py
).źródło
something
może to być moduł zewnętrzny, reż. coś jeszcze będzie działać. Dzięki za komentarz, zmodyfikuję swój post, aby był bardziej przejrzysty.Użycie
__init__.py
pliku pozwala uczynić wewnętrzną strukturę pakietu niewidoczną z zewnątrz. Jeśli struktura wewnętrzna ulegnie zmianie (np. Z powodu podzielenia jednego modułu fat na dwa), musisz tylko dostosować__init__.py
plik, ale nie kod, który zależy od pakietu. Możesz także uczynić części pakietu niewidocznymi, np. Jeśli nie są gotowe do ogólnego użytku.Zauważ, że możesz użyć
del
polecenia, więc typowe__init__.py
może wyglądać tak:from somemodule import some_function1, some_function2, SomeObject del somemodule
Teraz, jeśli zdecydujesz się podzielić,
somemodule
nowy__init__.py
może być:from somemodule1 import some_function1, some_function2 from somemodule2 import SomeObject del somemodule1 del somemodule2
Z zewnątrz opakowanie nadal wygląda dokładnie tak, jak poprzednio.
źródło
import <pack>.somemodule1
bezpośredniemu. Można importować tylko z<pack>
obiektów zdefiniowanych lub zaimportowanych w jego__init__.py
i nieusuniętych podmodułach.