Na init.py nie jest wymagane dla pakietów w Pythonie 3.3+

Używam Pythona 3.5.1. Przeczytałem dokument i sekcję pakiet tutaj: https://docs.python.org/3/tutorial/modules.html#packages

Teraz mam następującą strukturę:

/home/wujek/Playground/a/b/module.py

module.py:

class Foo:
    def __init__(self):
        print('initializing Foo')

Teraz, gdy w /home/wujek/Playground:

~/Playground $ python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x100a8f0b8>

Podobnie, teraz w domu, superfolder z Playground:

~ $ PYTHONPATH=Playground python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x10a5fee10>

Właściwie, mogę robić różne rzeczy:

~ $ PYTHONPATH=Playground python3
>>> import a
>>> import a.b
>>> import Playground.a.b

Dlaczego to działa? I thought there need to be __init__.py files (puste będą działać) zarówno w a jak i b dla module.py, aby można było importować, gdy ścieżka Pythona wskazuje na folder Playground?

Wydaje się, że to się zmieniło od Pythona 2.7:

~ $ PYTHONPATH=Playground python
>>> import a
ImportError: No module named a
>>> import a.b
ImportError: No module named a.b
>>> import a.b.module
ImportError: No module named a.b.module

Z __init__.py w obu ~/Playground/a i ~/Playground/a/b działa dobrze.

Author: smci, 2016-05-10

5 answers

Python 3.3 + posiada domyślne Pakiety przestrzeni nazw , które umożliwiają tworzenie pakietów bez pliku __init__.py.

Umożliwienie domyślnej przestrzeni nazw pakietów oznacza, że wymóg dostarczenia pliku __init__.py może zostać całkowicie usunięty, i może zostać naruszony ... .

Stary sposób z plikami __init__.py nadal działa jak w Pythonie 2.

 213
Author: Mike Müller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-13 01:46:16

Przegląd

@ Mike odpowiedź jest poprawna, ale zbyt nieprecyzyjna . To prawda, że Python 3.3 + obsługuje Ukryte Pakiety przestrzeni nazw , które pozwalają na utworzenie pakietu bez pliku __init__.py. Jest to pakiet przestrzeni nazw W przeciwieństwie do zwykłego pakietu, który ma Plik __init__.py (pusty lub nie pusty).

Jednak tworzenie pakietu przestrzeni nazw powinno być wykonywane tylko wtedy, gdy istnieje taka potrzeba. Dla większości przypadków użycia i deweloperzy tam, to nie ma zastosowania, więc należy trzymać się puste __init__.py / align = "left" /

Przypadek użycia pakietu przestrzeni nazw

Aby zademonstrować różnicę między dwoma typami pakietów Pythona, spójrzmy na poniższy przykład:

google_pubsub/              <- Package 1
    google/                 <- Namespace package (there is no __init__.py)
        cloud/              <- Namespace package (there is no __init__.py)
            pubsub/         <- Regular package (with __init__.py)
                __init__.py <- STILL REQUIRED to make the package a regular package and to run some initialization
                foo.py

google_storage/             <- Package 2
    google/                 <- Namespace package (there is no __init__.py)
        cloud/              <- Namespace package (there is no __init__.py)
            storage/        <- Regular package (with __init__.py)
                __init__.py <- STILL REQUIRED to make the package a regular package and to run some initialization
                bar.py

google_pubsub i google_storage są oddzielnymi pakietami, ale mają tę samą przestrzeń nazw google/cloud. Aby współdzielić tę samą przestrzeń nazw, wymagane jest, aby każdy katalog wspólnej ścieżki był pakietem przestrzeni nazw, tzn. google/ i cloud/. to powinien być jedyny przypadek użycia do tworzenia pakietów przestrzeni nazw, w przeciwnym razie nie ma takiej potrzeby.

Ważne jest, aby w katalogach google i google/cloud nie było plików __init__py, aby oba katalogi mogły być interpretowane jako pakiety przestrzeni nazw . W Pythonie 3.3 + każdy katalog sys.path z nazwą odpowiadającą wyszukiwanej nazwie pakietu będzie rozpoznawany jako moduły i podpakiety do tego pakietu. W rezultacie, podczas importu zarówno z google_pubsub, jak i google_storage, interpreter Pythona będzie w stanie je znaleźć.

Różni się to od zwykłych pakietów , które są samodzielne, co oznacza, że wszystkie części żyją w tej samej hierarchii katalogów. Gdy importowanie pakietu i interpreter Pythona napotka podkatalog sys.path z plikiem __init__.py, wtedy utworzy pojedynczy katalog zawierający tylko moduły z tego katalogu, zamiast znajdować wszystkie odpowiednio nazwane podkatalogi poza tym katalog. jest to idealne rozwiązanie dla pakietów, które nie chcą współdzielić przestrzeni nazw . Bardzo polecam zajrzeć do pułapek dla Unwary w systemie importowania Pythona, aby lepiej zrozumieć, jak zaimportowanie Pythona zachowuje się z pakietem regularnym i przestrzenią nazw oraz na jakie pułapki __init__.py Należy uważać.

Podsumowanie

  • pomiń tylko pliki __init__.py, jeśli chcesz utworzyć Pakiety przestrzeni nazw. Twórz tylko pakiety przestrzeni nazw, jeśli masz inne pakiety biblioteki, które znajdują się w różnych lokalizacjach i chcesz, aby każda z nich dodała podpakiet do pakietu nadrzędnego, tj. pakietu przestrzeni nazw.
  • dodawaj puste __init__py do swoich katalogów, ponieważ w 99% przypadków chcesz tylko tworzyć zwykłe Pakiety. Ponadto, narzędzia Pythona, takie jak mypy i pytest wymagają pustych plików __init__.py, aby odpowiednio zinterpretować strukturę kodu. Ponownie, może to prowadzić do dziwnych błędów, jeśli nie zostanie zrobione z care.

Zasoby

Moja odpowiedź dotyka tylko tego, jak działają zwykłe Pakiety i Pakiety przestrzeni nazw, więc zajrzyj do następujących zasobów, aby uzyskać więcej informacji:

 180
Author: arauter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-14 10:40:46

Jeśli masz setup.py w swoim projekcie i używasz find_packages() w jego obrębie, konieczne jest posiadanie pliku __init__.py w każdym katalogu, aby Pakiety mogły zostać automatycznie znalezione.

Pakiety są rozpoznawane tylko wtedy, gdy zawierają plik __init__.py

UPD: Jeśli chcesz użyć domyślnych pakietów przestrzeni nazw Bez __init__.py, musisz użyć find_namespace_packages() zamiast

Docs

 16
Author: techkuz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-12 15:26:37

Powiedziałbym, że należy pominąć __init__.py tylko wtedy, gdy chcemy mieć ukryty pakiet przestrzeni nazw . Jeśli nie wiesz, co to znaczy, prawdopodobnie nie chcesz go używać i dlatego powinieneś nadal używać __init__.py nawet w Pythonie 3.

 9
Author: Mi-La,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-05 08:29:54

Bazując na moim doświadczeniu, nawet z Pythonem 3.3+, pusty __init__.py jest nadal czasami potrzebny. Jedną z sytuacji jest to, gdy chcesz odnieść podfolder do pakietu. Na przykład, gdy uruchomiłem python -m test.foo, nie zadziałało, dopóki nie utworzyłem pustego __init__.py w folderze testowym. A ja mówię tu o wersji 3.6.6, która jest całkiem niedawno.

Poza tym, nawet ze względu na kompatybilność z istniejącym kodem źródłowym lub wytycznymi projektu, miło jest mieć puste __init__.py w folderze pakietu.

 3
Author: Prahlad Yeri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-28 04:08:58