Odpowiedzi:
Kiedyś była to wymagana część pakietu ( stary „zwykły pakiet” wcześniejszy niż 3.3 , a nie nowszy „pakiet przestrzeni nazw” w wersji 3.3+ ).
Python definiuje dwa typy pakietów, zwykłe pakiety i pakiety przestrzeni nazw. Zwykłe pakiety to tradycyjne pakiety, takie jakie istniały w Pythonie 3.2 i wcześniejszych. Zwykły pakiet jest zwykle implementowany jako katalog zawierający
__init__.py
plik. Po zaimportowaniu zwykłego pakietu__init__.py
plik ten jest domyślnie wykonywany, a definiowane przez niego obiekty są powiązane z nazwami w przestrzeni nazw pakietu.__init__.py
Plik może zawierać ten sam kod Pythona, że każdy inny moduł może zawierać i Python będzie dodać kilka dodatkowych atrybutów w module, gdy jest importowany.
Ale wystarczy kliknąć link, zawiera on przykład, więcej informacji i objaśnienie pakietów przestrzeni nazw, takich rodzajów pakietów bez __init__.py
.
sys.path.insert(0, '/path/to/datetime')
, zastępując tę ścieżkę ścieżką do dowolnego właśnie utworzonego katalogu. Teraz spróbuj czegoś takiego from datetime import datetime;datetime.now()
. Powinieneś dostać AttributeError (ponieważ teraz importuje twój pusty plik). Jeśli powtórzyłbyś te kroki bez tworzenia pustego pliku inicjującego, tak by się nie stało. Właśnie temu ma zapobiegać.
from datetime import datetime
bezbłędnie. To dobrze, aż do wersji 2.3!
builtins
wyświetla listę wbudowanych funkcji i klas , a nie wbudowanych modułów (por. Docs.python.org/3/tutorial/modules.html#the-dir-function ). Jeśli chcesz wyświetlić listę wbudowanych modułów , wykonaj import sys; print(sys.builtin_module_names)
(por. Docs.python.org/3/library/sys.html#sys.builtin_module_names ).
Nazwane pliki __init__.py
służą do oznaczania katalogów na dysku jako katalogów pakietów Pythona. Jeśli masz pliki
mydir/spam/__init__.py
mydir/spam/module.py
i mydir
jest na twojej drodze, możesz zaimportować kod module.py
jako
import spam.module
lub
from spam import module
Jeśli usuniesz __init__.py
plik, Python nie będzie już szukał podmodułów w tym katalogu, więc próby zaimportowania modułu zakończą się niepowodzeniem.
__init__.py
Plik jest zwykle pusty, ale może być używany do eksportowania wybranych fragmentów pakietu pod nazwą bardziej wygodny, funkcje convenience ładowni itp Biorąc pod uwagę powyższy przykład, zawartość modułu inicjującego mogą być dostępne jako
import spam
na tej podstawie
__init__.py
był wymagany w Pythonie 2.X i jest nadal wymagany w Pythonie 2.7.12 (przetestowałem go), ale nie jest już wymagany od (rzekomo) Python 3.3 i nie jest wymagany w Pythonie 3.4.3 (I przetestowałem to). Aby uzyskać więcej informacji, zobacz stackoverflow.com/questions/37139786 .
__init__.py
.
setup.py
i używasz, musisz find_packages()
mieć __init__.py
w każdym katalogu. Zobacz stackoverflow.com/a/56277323/7127824
Oprócz oznaczania katalogu jako pakietu Pythona i definiowania __all__
, __init__.py
pozwala zdefiniować dowolną zmienną na poziomie pakietu. Jest to często wygodne, jeśli pakiet definiuje coś, co będzie często importowane, w sposób podobny do API. Ten wzór promuje przestrzeganie filozofii Pythona, że „mieszkanie jest lepsze niż zagnieżdżone”.
Oto przykład z jednego z moich projektów, w którym często importuję sessionmaker
wywołanie w Session
celu interakcji z moją bazą danych. Napisałem pakiet „bazy danych” z kilkoma modułami:
database/
__init__.py
schema.py
insertions.py
queries.py
Mój __init__.py
zawiera następujący kod:
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)
Ponieważ Session
tutaj definiuję , mogę rozpocząć nową sesję przy użyciu poniższej składni. Ten kod byłby tak samo wykonywany wewnątrz lub na zewnątrz katalogu pakietu „bazy danych”.
from database import Session
session = Session()
Oczywiście jest to niewielka wygoda - alternatywą byłoby zdefiniowanie Session
w nowym pliku takim jak „create_session.py” w moim pakiecie bazy danych i rozpoczęcie nowych sesji przy użyciu:
from database.create_session import Session
session = Session()
Istnieje całkiem interesujący wątek reddit obejmujący odpowiednie zastosowania __init__.py
tutaj:
http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/
Wydaje się, że większość uważa, że __init__.py
pliki powinny być bardzo cienkie, aby uniknąć naruszenia filozofii „jawne jest lepsze niż dorozumiane”.
engine
, sessionmaker
, create_engine
, I os
wszystkie mogą być również importowane z database
teraz ... Wygląda na to zrobiłeś bałagan tej przestrzeni nazw.
__all__ = [...]
aby ograniczyć liczbę importowanych plików import *
. Ale poza tym tak, masz nieporządną przestrzeń nazw najwyższego poziomu.
Są 2 główne powody __init__.py
Dla wygody: inni użytkownicy nie będą musieli znać dokładnej lokalizacji Twoich funkcji w hierarchii pakietów.
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
wtedy inni mogą wywołać add () przez
from your_package import add
bez znajomości file1, na przykład
from your_package.file1 import add
Jeśli chcesz coś zainicjować; na przykład rejestrowanie (które należy umieścić na najwyższym poziomie):
import logging.config
logging.config.dictConfig(Your_logging_config)
__init__.py
może być przydatne czasem, ale nie zawsze.
__init__.py
Plik sprawia Python katalogów zawierających je traktować jako moduły.
Ponadto jest to pierwszy plik ładowany do modułu, więc można go użyć do wykonania kodu, który chcesz uruchomić za każdym razem, gdy moduł jest ładowany, lub określić submoduły, które mają zostać wyeksportowane.
Od wersji Python 3.3 __init__.py
nie jest już wymagane definiowanie katalogów jako importowalnych pakietów Pythona.
Sprawdź PEP 420: Pakiety niejawnej przestrzeni nazw :
Natywne wsparcie dla katalogów pakietów, które nie wymagają
__init__.py
plików znaczników i mogą automatycznie obejmować wiele segmentów ścieżek (inspirowane różnymi podejściami stron trzecich do pakietów przestrzeni nazw, jak opisano w PEP 420 )
Oto 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
referencje:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
Czy __init__. py nie jest wymagane dla pakietów w Pythonie 3?
W Pythonie definicja pakietu jest bardzo prosta. Podobnie jak Java, struktura hierarchiczna i struktura katalogów są takie same. Ale musisz mieć __init__.py
w pakiecie. Wyjaśnię __init__.py
plik na poniższym przykładzie:
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__.py
może być pusty, o ile istnieje. Wskazuje, że katalog należy traktować jako pakiet. Oczywiście,__init__.py
można również ustawić odpowiednią treść.
Jeśli dodamy funkcję w module_n1:
def function_X():
print "function_X in module_n1"
return
Po bieganiu:
>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()
function_X in module_n1
Następnie postępowaliśmy zgodnie z pakietem hierarchii i nazwaliśmy moduł_n1 funkcją. Możemy użyć __init__.py
w subPackage_b w następujący sposób:
__all__ = ['module_n2', 'module_n3']
Po bieganiu:
>>>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
Dlatego przy użyciu * importowania pakiet modułów jest zależny od __init__.py
zawartości.
from package_x.subPackage_b.module_n1 import function_X
Chociaż Python działa bez __init__.py
pliku, nadal powinieneś go dołączyć.
Określa, że pakiet powinien być traktowany jako moduł, dlatego dołącz go (nawet jeśli jest pusty).
Istnieje również przypadek, w którym możesz faktycznie użyć __init__.py
pliku:
Wyobraź sobie, że masz następującą strukturę plików:
main_methods
|- methods.py
I methods.py
zawierał to:
def foo():
return 'foo'
Aby go użyć foo()
, potrzebujesz jednego z poniższych:
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()
Być może potrzebujesz (lub chcesz) pozostać w methods.py
środku main_methods
(na przykład środowiska wykonawcze / zależności), ale chcesz tylko zaimportować main_methods
.
Jeśli zmieniłeś nazwę methods.py
na, __init__.py
możesz użyć foo()
, importując main_methods
:
import main_methods
print(main_methods.foo()) # Prints 'foo'
Działa __init__.py
to, ponieważ jest traktowane jako część pakietu.
Niektóre pakiety Pythona faktycznie to robią. Przykładem jest JSON , w którym uruchomiony import json
jest import __init__.py
z json
pakietu ( zobacz tutaj strukturę pliku pakietu ):
Kod źródłowy:
Lib/json/__init__.py
__init__.py
potraktuje katalog, w którym się znajduje, jako moduł do załadowania.
Dla osób, które wolą czytać kod, zamieszczam tutaj komentarz Two-Bit Alchemist .
$ 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
>>>
Ułatwia importowanie innych plików Pythona. Kiedy umieścisz ten plik w katalogu (powiedzmy rzeczy) zawierającym inne pliki py, możesz zrobić coś takiego jak import rzeczy. Inne.
root\
stuff\
other.py
morestuff\
another.py
Bez tego __init__.py
wewnątrz katalogu nie można zaimportować pliku other.py, ponieważ Python nie wie, gdzie jest kod źródłowy rzeczy i nie jest w stanie rozpoznać go jako pakietu.
__init__.py
Plik sprawia importu łatwe. Gdy __init__.py
w pakiecie jest obecny, funkcję a()
można zaimportować z pliku w następujący b.py
sposób:
from b import a
Bez niego nie można jednak importować bezpośrednio. Musisz zmienić ścieżkę systemową:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a