Czy __init__.py nie jest wymagany dla pakietów w Pythonie 3.3+

195

Używam Python 3.5.1. Przeczytałem tutaj dokument i pakiet: 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, będąc 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 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 choć nie musiał być __init__.pypliki (pustych będzie działać) w obu ai bdla module.pyaby być importable gdy pytona punkty ścieżka do Playgroundfolderu?

Wygląda na to, że zmieniło się to z Python 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__.pyobu ~/Playground/ai ~/Playground/a/bdziała dobrze.

wujek
źródło

Odpowiedzi:

192

Python 3.3+ ma niejawne pakiety przestrzeni nazw, które pozwalają mu tworzyć pakiety bez __init__.pypliku.

Zezwolenie na niejawne pakiety przestrzeni nazw oznacza, że ​​wymóg dostarczenia __init__.pypliku można całkowicie usunąć i wpłynąć na ...

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

Mike Müller
źródło
10
Przeczytam dokument, ale jest trochę długi. Czy można szybko podsumować? Czy możesz mi tylko powiedzieć: czy nadal obsługuje plik init .py, czy całkowicie go ignoruje? Jeśli je obsługuje, to jaka jest różnica w funkcjonalności i dlaczego ta dualność?
wujek
3
Samouczek powinien być prawdopodobnie zaktualizowany. Czy został dla niej otwarty błąd w dokumentacji?
Michel Samia
4
Nadal jestem zdenerwowany, że to Zen Of PythonExplicit is better than implicit.
przeczy
5
@JayRizzo But: „Chociaż praktyczność przewyższa czystość”.
Mike Müller,
19
@JayRizzo IMO jest jeszcze bardziej wyraźny. Czasami zdarza się, że robi się rzeczy inicjujące __init__.py, a czasem nie. Kiedy potrzebuję tych rzeczy w Pythonie 3, tworzę nowy __init__.pyze specyficznym kodem, inaczej nie. Przydaje się to, aby wizualnie wiedzieć, które pakiety mają niestandardowe init. Zamiast tego w Pythonie 2 zawsze muszę umieścić __init__.py(często pusty), co sprawia, że ​​jest ich ogromna liczba, a na koniec trudniej zapamiętać, gdzie umieściłeś swój kod init. Powinno to również pasować „Powinien być jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego”.
Paolo
148

WAŻNY

@ Odpowiedź Mike'a jest poprawna, ale zbyt nieprecyzyjna. Prawdą jest, że Python 3.3+ obsługuje pakiety Implicit Namespace, które pozwalają mu tworzyć pakiet bez __init__.pypliku.

Dotyczy to TYLKO plików EMPTY__init__.py . Więc EMPTY__init__.py pliki nie są już potrzebne i można je pominąć. Jeśli chcesz uruchomić określony skrypt inicjujący podczas importowania pakietu lub dowolnego z jego modułów lub podpakietów, nadal potrzebujesz __init__.pypliku. Jest to świetna odpowiedź na pytanie o przepełnienie stosu, dlaczego chcesz użyć __init__.pypliku do przeprowadzenia dalszej inicjalizacji w przypadku, gdy zastanawiasz się, dlaczego jest to w ogóle przydatne.

Przykład struktury katalogów:

  parent_package/
     __init__.py            <- EMPTY, NOT NECESSARY in Python 3.3+
     child_package/
          __init__.py       <- STILL REQUIRED if you want to run an initialization script
          child1.py
          child2.py
          child3.py

parent_package/child_package/__init__.py:

print("from parent")

PRZYKŁADY

Poniższe przykłady pokazują, w jaki sposób skrypt inicjujący jest wykonywany podczas child_packageimportowania jednego lub jednego z jego modułów.

Przykład 1 :

from parent_package import child_package  # prints "from parent"

Przykład 2 :

from parent_package.child_package import child1  # prints "from parent"
arauter
źródło
2
Załóżmy, że mam ten run_script.pysam katalog, co parent_packagemogę importować jak from parent_package.child_package import child1bez __init__.py?
mrgloom
Czy ma to na celu napisanie child_package.some_function, nawet jeśli jakaś funkcja jest zdefiniowana w childX.py? Innymi słowy, unika to wymagania od użytkownika znajomości różnych plików w child_package? ?
johnbakers,
Tak, nie rozumiem, dlaczego miałbyś to robić child1.py, child2.pyzamiast po prostu składać ich kod __init__bezpośrednio w .py.
binki
Czy deklaracje importowe nie powinny __init__być importami względnymi, tj. from . import child1? Absolutny import daje mi ModuleNotFoundError(w Pythonie 3.6)
Halbeard
5
Z mojego doświadczenia wynika, że ​​nawet w Pythonie 3.3+ pusty __init__.pyjest czasem potrzebny, na przykład gdy chcesz odwołać się do podfolderu jako pakietu. Na przykład, jeśli uruchomię python -m test.foo, nie zadziała, dopóki nie utworzę pustego __init__.pyfolderu testowego. Mówię tutaj o wersji 3.6.6!
Prahlad Yeri
7

Jeśli masz setup.pyswój projekt i korzystasz z find_packages()niego, konieczne jest posiadanie __init__.pypliku w każdym katalogu, aby pakiety mogły zostać automatycznie znalezione.

Pakiety są rozpoznawane tylko wtedy, gdy zawierają __init__.pyplik

UPD : Jeśli chcesz korzystać z niejawnych pakietów przestrzeni nazw, __init__.pymusisz po prostu użyć find_namespace_packages()zamiast tego

Dokumenty

techkuz
źródło
1

Powiedziałbym, że należy pominąć __init__.pytylko wtedy, gdy ktoś chce mieć pakiet niejawnej przestrzeni nazw . Jeśli nie wiesz, co to znaczy, prawdopodobnie nie chcesz tego i dlatego powinieneś nadal używać __init__.pyparzystości w Pythonie 3.

Mi-La
źródło