Zgodnie z komentarzem poniżej autorstwa @Rob_before_edits i tego wątku 37139786 w przepływie stosów , wydaje się, że init .py nie jest już potrzebny w Pythonie 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__.pyplik. Po zaimportowaniu zwykłego pakietu __init__.pyplik ten jest domyślnie wykonywany, a definiowane przez niego obiekty są powiązane z nazwami w przestrzeni nazw pakietu. __init__.pyPlik 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.
Co to znaczy: „ma to na celu zapobieżenie przypadkowemu ukryciu przez katalogi o wspólnej nazwie, takiej jak łańcuch znaków, prawidłowych modułów pojawiających się później na ścieżce wyszukiwania modułów”?
Carl G
97
@CllG Python przeszukuje listę katalogów w celu rozpoznania nazw, np. Instrukcji importu. Ponieważ mogą to być dowolne katalogi, a użytkownik końcowy może dodać dowolne, programiści muszą się martwić o katalogi, które mogą dzielić nazwę z prawidłowym modułem Pythona, takim jak „string” w przykładzie docs. Aby temu zaradzić, ignoruje katalogi, które nie zawierają pliku o nazwie _ _ init _ _.py (bez spacji), nawet jeśli jest pusty.
Two-Bit Alchemist
186
@CarlG Wypróbuj to. Utwórz katalog o nazwie „datetime”, w którym utworzą dwa puste pliki, plik init.py (z podkreśleniami) i datetime.py. Teraz otwórz interpreter, zaimportuj system i wydaj 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ć.
Two-Bit Alchemist
4
@ DarekNędza Masz coś niepoprawnie skonfigurowanego, jeśli nie możesz po prostu otworzyć interpretera języka Python i wydać go from datetime import datetimebezbłędnie. To dobrze, aż do wersji 2.3!
Nazwane pliki __init__.pysł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 mydirjest na twojej drodze, możesz zaimportować kod module.pyjako
import spam.module
lub
from spam import module
Jeśli usuniesz __init__.pyplik, Python nie będzie już szukał podmodułów w tym katalogu, więc próby zaimportowania modułu zakończą się niepowodzeniem.
__init__.pyPlik 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
Aktualizacja: Plik __init__.pybył 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 .
Rob_before_edits
4
Nie używaj tego. Jest to pakiet „przestrzeni nazw”, a nie zwykły pakiet. pakiet przestrzeni nazw jest używany w bardzo rzadkich przypadkach użycia. Być może nie będziesz musiał wiedzieć, kiedy go używać. Po prostu użyj __init__.py.
Oprócz oznaczania katalogu jako pakietu Pythona i definiowania __all__, __init__.pypozwala 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”.
Przykład
Oto przykład z jednego z moich projektów, w którym często importuję sessionmakerwywołanie w Sessioncelu interakcji z moją bazą danych. Napisałem pakiet „bazy danych” z kilkoma modułami:
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])Session= sessionmaker(bind=engine)
Ponieważ Sessiontutaj 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 importSession
session =Session()
Oczywiście jest to niewielka wygoda - alternatywą byłoby zdefiniowanie Sessionw nowym pliku takim jak „create_session.py” w moim pakiecie bazy danych i rozpoczęcie nowych sesji przy użyciu:
from database.create_session importSession
session =Session()
Dalsza lektura
Istnieje całkiem interesujący wątek reddit obejmujący odpowiednie zastosowania __init__.pytutaj:
engine, sessionmaker, create_engine, I oswszystkie mogą być również importowane z databaseteraz ... Wygląda na to zrobiłeś bałagan tej przestrzeni nazw.
ArtOfWarfare
9
@ArtOfWarfare, możesz użyć, __all__ = [...]aby ograniczyć liczbę importowanych plików import *. Ale poza tym tak, masz nieporządną przestrzeń nazw najwyższego poziomu.
Nathan Gould,
Czy mogę wiedzieć, jaki jest „URL BAZY DANYCH”? Próbowałem to zreplikować, dołączając silnik create_ do 'mysql + mysqldb: // root: python @ localhost: 3306 / test', ale to nie działa. Dzięki.
SunnyBoiz
2
Jak uzyskasz dostęp do klasy „Sesja” zdefiniowanej w init od wewnątrz pakietu, np. Quieries.py?
vldbnc
252
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.
och, zanim przeczytałem twoją odpowiedź, pomyślałem, że wywołanie funkcji wprost z jej lokalizacji jest dobrą praktyką.
Aerin
2
@Aerin lepiej byłoby nie uważać krótkich stwierdzeń (lub w tym przypadku subiektywnych wniosków) za zawsze prawdziwe. Importowanie z __init__.pymoże być przydatne czasem, ale nie zawsze.
Tobias Sette,
2
Czy te kody są wykonywane podczas importu lub w czasie wykonywania?
user1559897
111
__init__.pyPlik 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.
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 )
W Pythonie definicja pakietu jest bardzo prosta. Podobnie jak Java, struktura hierarchiczna i struktura katalogów są takie same. Ale musisz mieć __init__.pyw pakiecie. Wyjaśnię __init__.pyplik na poniższym przykładzie:
__init__.pymoż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__.pyw 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__.pyzawartości.
Jak mój setup.py będzie wyglądał, aby wykonać ten sam import przez spakowaną bibliotekę? from package_x.subPackage_b.module_n1 import function_X
technazi
więc kluczem jest tutaj: „przy użyciu * importowania, pakiet modułów podlega inicjalizacji .py zawartości”
Minnie
54
Chociaż Python działa bez __init__.pypliku, 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__.pypliku:
Wyobraź sobie, że masz następującą strukturę plików:
main_methods
|- methods.py
I methods.pyzawierał 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.pyna, __init__.pymożesz użyć foo(), importując main_methods:
import main_methods
print(main_methods.foo())# Prints 'foo'
Działa __init__.pyto, ponieważ jest traktowane jako część pakietu.
Niektóre pakiety Pythona faktycznie to robią. Przykładem jest JSON , w którym uruchomiony import jsonjest import __init__.pyz jsonpakietu ( zobacz tutaj strukturę pliku pakietu ):
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__.pywewną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.
Mam taką samą strukturę w moim projekcie (python 3.4), ale nie jestem w stanie zrobić pliku another.py zobacz other.py. Jak powinienem dokonać importu? z root.stuff importować inne? Działa w trybie debugowania VSCode, ale nie w wierszu poleceń. Jakieś pomysły?
rodrigorf
10
__init__.pyPlik sprawia importu łatwe. Gdy __init__.pyw pakiecie jest obecny, funkcję a()można zaimportować z pliku w następujący b.pysposó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
co masz na myśli: „ funkcję a () można importować z pliku b.py [snippet] Bez tego nie można jednak importować bezpośrednio. ”? Mogę zaimportować funkcję a () z pliku b.py bez __init__.py.
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+ ).
Oto dokumentacja.
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
.źródło
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ś takiegofrom 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 , wykonajimport 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 plikii
mydir
jest na twojej drodze, możesz zaimportować kodmodule.py
jakolub
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 jakona tej podstawie
źródło
__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, musiszfind_packages()
mieć__init__.py
w każdym katalogu. Zobacz stackoverflow.com/a/56277323/7127824Opró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”.Przykład
Oto przykład z jednego z moich projektów, w którym często importuję
sessionmaker
wywołanie wSession
celu interakcji z moją bazą danych. Napisałem pakiet „bazy danych” z kilkoma modułami:Mój
__init__.py
zawiera następujący kod: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”.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:Dalsza lektura
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”.źródło
engine
,sessionmaker
,create_engine
, Ios
wszystkie mogą być również importowane zdatabase
teraz ... Wygląda na to zrobiłeś bałagan tej przestrzeni nazw.__all__ = [...]
aby ograniczyć liczbę importowanych plikówimport *
. 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.
wtedy inni mogą wywołać add () przez
bez znajomości file1, na przykład
Jeśli chcesz coś zainicjować; na przykład rejestrowanie (które należy umieścić na najwyższym poziomie):
źródło
__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.
źródło
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 :
Oto test:
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?
źródło
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:__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:
Po bieganiu:
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:Po bieganiu:
Dlatego przy użyciu * importowania pakiet modułów jest zależny od
__init__.py
zawartości.źródło
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:
I
methods.py
zawierał to:Aby go użyć
foo()
, potrzebujesz jednego z poniższych:Być może potrzebujesz (lub chcesz) pozostać w
methods.py
środkumain_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ącmain_methods
: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
zjson
pakietu ( zobacz tutaj strukturę pliku pakietu ):źródło
__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 .
źródło
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.
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.źródło
__init__.py
Plik sprawia importu łatwe. Gdy__init__.py
w pakiecie jest obecny, funkcjęa()
można zaimportować z pliku w następującyb.py
sposób:Bez niego nie można jednak importować bezpośrednio. Musisz zmienić ścieżkę systemową:
źródło