6. Moduły
*********

Jeśli wyjdziesz z interpretera Pythona i wejdziesz do niego z
powrotem, zauważysz, że straciłeś(-łaś) definicje, które
zrobiłeś(-łaś) (funkcje i zmienne). Z tego powodu, jeśli chcesz
napisać nieco dłuższy program, lepiej będzie użyć edytora tekstu, aby
przygotować wejście dla interpretera i uruchomić go z tym plikiem jako
wejściem. Znane jest to jako tworzenie „skryptu”. Kiedy twój program
staje się dłuższy, możesz podzielić go na kilka plików dla
łatwiejszego utrzymania. Możesz chcieć też użyć przydatnej funkcji,
którą napisałeś, w kilku programach, bez kopiowania jej definicji do
każdego programu.

By to zapewnić, Python ma możliwość umieszczania definicji w pliku i
używania ich w skrypcie lub w interaktywnej instancji interpretera.
Taki plik nazywa się *modułem*; definicje z modułu mogą być
*importowane* do innych modułów lub do modułu *main* (zbiór zmiennych,
do których masz dostęp w skrypcie wykonywanym na najwyższym poziomie i
w trybie kalkulatora).

Moduł to plik zawierający definicje i instrukcje Pythona. Nazwą pliku
jest nazwa modułu z dodanym sufiksem ".py". Wewnątrz modułu, jego
nazwa (jako ciąg znaków) jest dostępna jako wartość zmiennej globalnej
"__name__". Na przykład użyj swojego ulubionego edytora tekstu, by
stworzyć plik o nazwie "fibo.py" w bieżącym katalogu, z następującą
zawartością:

   # moduł liczb Fibonacciego

   def fib(n):    # wypisz ciąg Fibonacieggo do n
       a, b = 0, 1
       while a < n:
           print(a, end=' ')
           a, b = b, a+b
       print()

   def fib2(n):   # zwróć ciąg Fibonacciego do n
       result = []
       a, b = 0, 1
       while a < n:
           result.append(a)
           a, b = b, a+b
       return result

Teraz wejdź w interpreter Pythona i zaimportuj ten moduł następującą
komendą:

   >>> import fibo

Ta komenda nie dodaje nazw funkcji określonych w "fibo" bezpośrednio w
bieżącej *przestrzeni nazw* (więcej szczegółów w Zasięgi widoczności i
przestrzenie nazw w Pythonie); dodaje ona tam tylko nazwę modułu
"fibo". Używając nazwy modułu możesz użyć funkcji:

   >>> fibo.fib(1000)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
   >>> fibo.fib2(100)
   [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
   >>> fibo.__name__
   'fibo'

Jeśli zamierzasz używać funkcji często, możesz przypisać ją do
lokalnej nazwy:

   >>> fib = fibo.fib
   >>> fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377


6.1. Więcej o modułach
======================

Moduł może zawierać zarówno wykonywalne instrukcje jak i definicje
funkcji. Instrukcje mają inicjalizować moduł. Są wykonywane tylko za
*pierwszym* razem, gdy nazwa modułu zostanie napotkana w instrukcji
importu. [1] (Są one również wykonywane, jeśli plik jest wykonywany
jako skrypt.)

Każdy moduł ma swoją własną przestrzeń nazw, która jest używana jako
globalna przestrzeń nazw przez wszystkie funkcje zdefiniowane w tym
module. Tak więc autor modułu może używać globalnych zmiennych nie
martwiąc się o przypadkowe konflikty z globalnymi zmiennymi
użytkownika. Z drugiej strony, jeśli wiesz co robisz, możesz odnosić
się do globalnych zmiennych modułu tą samą notacją, którą używa się do
odniesień do jego funkcji, "nazwamodułu.nazwalementu".

Moduły mogą importować inne moduły. Zwyczajowo (nieobowiązkowo)
umieszcza się wszystkie instrukcje "import" na początku modułu (lub
skryptu). Zaimportowane nazwy modułów, jeśli są umieszczone na
najwyższym poziomie modułu (poza jakimikolwiek funkcjami lub klasami),
są umieszczane w globalnej przestrzeni nazw modułu.

Istnieje wariant instrukcji "import", który importuje nazwy z modułu
bezpośrednio do przestrzeni nazw modułu importującego. Na przykład:

   >>> from fibo import fib, fib2
   >>> fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Nie wprowadza to nazwy modułu, z którego wzięte są importy, do
lokalnej przestrzeni nazw (więc w przykładzie "fibo" nie jest
zdefiniowane).

Jest również wariant importujący wszystkie nazwy definiowane przez
moduł:

   >>> from fibo import *
   >>> fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Importuje to wszystkie nazwy z wyjątkiem tych zaczynających się od
podkreślenia ("_"). Najczęściej programiści Pythona nie używają tego
udogodnienia, ponieważ wprowadza ono nieznany zestaw nazw do
interpretera, być może ukrywając niektóre już zdefiniowane rzeczy.

Zwróć uwagę, że ogólnie praktyka importowania "*" z modułu lub pakietu
jest niemile widziana, ponieważ często powoduje, że kod jest mało
czytelny. Można jej jednak używać do oszczędzania pisania w sesjach
interaktywnych.

Jeżeli po nazwie modułu następuje "as", to nazwa następująca po "as"
jest powiązana bezpośrednio z importowanym modułem.

   >>> import fibo as fib
   >>> fib.fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

W praktyce jest to importowanie modułu w taki sam sposób, jak robi to
"import fibo", z tą różnicą, że jest on dostępny jako "fib".

Można go również użyć przy użyciu "from" z podobnym efektem:

   >>> from fibo import fib as fibonacci
   >>> fibonacci(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Informacja:

  Ze względów wydajnościowych każdy moduł jest importowany tylko raz
  dla sesji interpretera. W związku z tym jeśli zmienisz swoje moduły,
  musisz zrestartować interpreter – lub, jeśli to tylko jeden moduł,
  który chcesz testować interaktywnie, użyj "importlib.reload()", na
  przykład "import importlib; importlib.reload(modulename)".


6.1.1. Wykonywanie modułów jako skryptów
----------------------------------------

Kiedy uruchamiasz moduł Pythona:

   python fibo.py <arguments>

kod w module zostanie wykonany, tak jakbyś go zaimportował, ale z
"__name__" ustawionym na ""__main__"". To oznacza, że dodając ten kod
na końcu swojego modułu:

   if __name__ == "__main__":
       import sys
       fib(int(sys.argv[1]))

możesz uczynić plik używalnym zarówno jako skrypt oraz jako
importowalny moduł, ponieważ kod, który parsuje linię komend uruchamia
się tylko jeśli moduł jest wykonywany jako plik „główny”:

   $ python fibo.py 50
   0 1 1 2 3 5 8 13 21 34

Jeśli moduł jest zaimportowany, kod nie jest uruchamiany:

   >>> import fibo
   >>>

Często się z tego korzysta, aby dodać wygodny interfejs użytkownika do
modułu lub na potrzeby testów (uruchomienie modułu jako skryptu
wykonuje zestaw testów).


6.1.2. Ścieżka wyszukiwania modułów
-----------------------------------

Kiedy importowany jest moduł o nazwie "spam", interpreter najpierw
szuka wbudowanego modułu o takiej nazwie. Te nazwy modułów znajdują
się w "sys.builtin_module_names". Jeśli nie znajdzie, wtedy szuka
pliku o nazwie "spam.py" na liście katalogów danych w zmiennej
"sys.path". "sys.path" jest inicjalizowane z tych lokalizacji:

* Katalog zawierający skrypt wejściowy (lub bieżący katalog, jeśli
  plik nie jest określony).

* "PYTHONPATH" (lista nazw katalogów o takiej samej składni jak
  zmienna shell "PATH").

* Wartość domyślna zależna od instalacji (przez konwencję zawierająca
  katalog "site-packages", obsługiwany przez moduł "site").

Więcej szczegółów można znaleźć w The initialization of the sys.path
module search path.

Informacja:

  W systemach plików wspierających dowiązania symboliczne, katalog
  zawierający skrypt wejściowy jest wyliczany po rozwiązaniu
  dowiązania symbolicznego. Innymi słowy katalog zawierający
  dowiązanie symboliczne **nie** jest dodany do ścieżki wyszukiwania
  modułów.

Po inicjalizacji programy pythonowe mogą modyfikować "sys.path".
Katalog zwierający uruchamiany skrypt jest umieszczony na początku
ścieżki wyszukiwania, przed ścieżką biblioteki standardowej. To
znaczy, że skrypty w tym katalogu zostaną załadowane zamiast modułów o
tej samej nazwie w katalogu biblioteki. Jest to błąd, o ile taka
zamiana jest zamierzona. Patrz sekcja Moduły standardowe po więcej
informacji.


6.1.3. „Skompilowane” pliki Pythona
-----------------------------------

Aby przyspieszyć ładowanie modułów, Python cache'uje skompilowaną
wersję każdego modułu w katalogu "__pycache__" pod nazwą
"module.*wersja*.pyc", gdzie wersja koduje format skompilowanego
pliku; zazwyczaj zawiera numer wersji Pythona. Na przykład w wydaniu
CPythona 3.3 skompilowana wersja spam.py zostałaby zcache'owana jako
"__pycache__/spam.cpython-33.pyc". Ta konwencja nazw pozwala na
współistnienie skompilowanych modułów z różnych wydań i wersji
Pythona.

Python porównuje datę modyfikacji źródła ze skompilowaną wersją, aby
ustalić, czy jest przeterminowana i powinna zostać zrekompilowana. To
całkowicie automatyczny proces. Skompilowane moduły są niezależne od
platformy, więc ta sama biblioteka może być współdzielona pomiędzy
systemami z innymi architekturami.

Python nie sprawdza cache'u w dwóch przypadkach. Po pierwsze zawsze
rekompiluje i nie zapisuje wyniku dla modułu załadowanego bezpośrednio
z linii komend. Po drugie nie sprawdza cache'u, kiedy nie ma modułu
źródłowego. Dla wsparcia dystrybucji bez źródła (tylko kompilowany),
skompilowany moduł musi być w katalogu źródłowym i nie może być modułu
źródłowego.

Wskazówki dla ekspertów:

* Możesz użyć przełączników "-O" lub "-OO" na komendzie "python", aby
  zmniejszyć rozmiar skompilowanego modułu. Przełącznik "-O" usuwa
  instrukcje assert. Przełącznik "-OO" usuwa zarówno instrukcje assert
  jak i docstringi. Jako że niektóre programy mogą polegać na
  dostępności powyższych, powinieneś(-nnaś) używać tylko jeśli wiesz,
  co robisz. „Zoptymalizowane” moduły mają tag "opt-" i zazwyczaj są
  mniejsze. Przyszłe wydania mogą zmienić efekty optymalizacji.

* Program nie wykonuje się ani chwili szybciej, gdy jest czytany z
  pliku ".pyc" niż gdy jest czytany z pliku ".py". Jedyna rzecz, która
  jest szybsza w plikach ".pyc" to szybkość, w jakiej są one ładowane.

* Moduł "compileall" może stworzyć pliki .pyc dla wszystkich modułów w
  katalogu.

* Więcej szczegółów na temat tego procesu, w tym diagram przepływu
  decyzji, znajduje się w **PEP 3147**.


6.2. Moduły standardowe
=======================

Python zawiera bibliotekę modułów standardowych, opisaną w osobnym
dokumencie, dokumentacji biblioteki standardowej. Niektóre moduły są
wbudowane w interpreter; dają one dostęp do operacji, które nie są
częścią trzonu języka, niemniej jednak są wbudowane, dla wydajności
lub aby dać dostęp do elementów systemu operacyjnego jak wywołania
systemowe. Zbiór takich modułów jest opcją konfiguracyjną, która
zależy również od platformy. Na przykład moduł "winreg" jest dostępny
tylko w systemach Windows. Jeden szczególny moduł zasługuje na uwagę:
"sys", który jest wbudowany w każdy interpreter Pythona. Zmienne
"sys.ps1" i "sys.ps2" określają ciągi znaków używane jako znaki
zachęty pierwszego i drugiego rzędu:

   >>> import sys
   >>> sys.ps1
   '>>> '
   >>> sys.ps2
   '... '
   >>> sys.ps1 = 'C> '
   C> print('Ble!')
   Ble!
   C>

Te dwie zmienne są określone tylko jeśli interpreter jest w trybie
interaktywnym.

Zmienna "sys.path" jest listą ciągów znaków, która określa ścieżkę
wyszukań modułów interpretera. Jest inicjalizowana domyślą ścieżką
braną ze zmiennej środowiskowej "PYTHONPATH" lub z wbudowanej wartości
domyślnej, jeśli "PYTHONPATH" jest nieustawiona. Możesz ją modyfikować
używając standardowych operacji na listach:

   >>> import sys
   >>> sys.path.append('/ufs/guido/lib/python')


6.3. Funkcja "dir()"
====================

Wbudowana funkcja "dir()" jest używana do sprawdzenia, jakie nazwy
definiuje moduł. Zwraca uporządkowaną listę ciągów znaków:

   >>> import fibo, sys
   >>> dir(fibo)
   ['__name__', 'fib', 'fib2']
   >>> dir(sys)  
   ['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
    '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
    '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
    '_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
    '_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
    'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
    'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing',
    'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info',
    'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info',
    'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
    'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
    'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
    'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
    'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
    'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
    'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
    'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
    'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
    'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
    'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info',
    'warnoptions']

Bez argumentów, "dir()" wypisuje nazwy zdefiniowane w bieżącym
kontekście:

   >>> a = [1, 2, 3, 4, 5]
   >>> import fibo
   >>> fib = fibo.fib
   >>> dir()
   ['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']

Zauważ, że wylistowuje wszystkie typy nazw: zmienne, moduły, funkcje i
tak dalej.

"dir()" nie wypisuje nazw wbudowanych funkcji i zmiennych. Jeśli
chcesz ich listę, określone one są w module standardowym "builtins":

   >>> import builtins
   >>> dir(builtins)  
   ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',
    'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning',
    'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError',
    'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning',
    'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
    'FileExistsError', 'FileNotFoundError', 'FloatingPointError',
    'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
    'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError',
    'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
    'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
    'NotImplementedError', 'OSError', 'OverflowError',
    'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
    'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
    'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
    'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError',
    'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError',
    'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
    'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__',
    '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs',
    'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable',
    'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits',
    'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit',
    'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr',
    'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass',
    'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview',
    'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property',
    'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
    'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars',
    'zip']


6.4. Pakiety
============

Pakiety to sposób strukturyzacji przestrzeni nazw modułów Pythona za
pomocą „nazw modułów z kropkami”. Na przykład nazwa modułu "A.B"
oznacza podmoduł "B" nazwany w pakiecie o nazwie "A". Tak jak użycie
modułów oszczędza autorom martwienia się o nazwy zmiennych globalnych
w pozostałych modułach, użycie nazw modułów z kropkami oszczędza
autorom pakietów wielomodułowych, takich jak NumPy lub Pillow,
martwienie się o przestrzeń nazw innych podmodułów.

Załóżmy, że chcesz zaprojektować zbiór modułów („pakiet”) do
jednolitej obsługi plików dźwiękowych i danych dźwiękowych. Istnieje
wiele różnych formatów plików dźwiękowych (zwykle rozpoznawanych po
ich rozszerzeniach, na przykład: ".wav", ".aiff", ".au"), więc może
być konieczne utworzenie i utrzymywanie rosnącej kolekcji modułów do
konwersji między różnymi formatami plików. Istnieje również wiele
różnych operacji, które możesz chcieć wykonać na danych dźwiękowych
(takich jak miksowanie, dodawanie echa, stosowanie funkcji korektora,
tworzenie sztucznego efektu stereo), więc dodatkowo będziesz pisać
niekończącą się liczbę modułów do wykonywania tych operacji. Oto
możliwa struktura twojego pakietu (wyrażona jako hierarchiczny system
plików):

   sound/                          Pakiet najwyższego poziomu
         __init__.py               Inicjalizacja pakietu sound
         formats/                  Podpakiet do konwersji formatu plików
                 __init__.py
                 wavread.py
                 wavwrite.py
                 aiffread.py
                 aiffwrite.py
                 auread.py
                 auwrite.py
                 ...
         effects/                  Podpakiet do efektów dźwiękowych
                 __init__.py
                 echo.py
                 surround.py
                 reverse.py
                 ...
         filters/                  Podpakiet dla filtrów
                 __init__.py
                 equalizer.py
                 vocoder.py
                 karaoke.py
                 ...

Podczas importowania pakietu Python przeszukuje katalogi zapisane w
"sys.path" w poszukiwaniu podkatalogu pakietu.

Pliki "__init__.py" są wymagane, aby Python traktował katalogi
zawierające ten plik jako pakiety (o ile nie używa się *namespace
package*, dość zaawansowanej funkcji). Zapobiega to katalogom o często
występującej nazwie, takiej jak "string", przed niezamierzonym
ukrywaniem prawidłowych modułów, które pojawiają się później w ścieżce
wyszukiwania modułów. W najprostszym przypadku "__init__.py" może to
być po prostu pustym plikiem, ale może też wykonać kod inicjujący
pakiet lub ustawić zmienną "__all__", która będzie opisana później.

Użytkownicy pakietu mogą importować z pakietu poszczególne moduły, na
przykład:

   import sound.effects.echo

Spowoduje to załadowanie podmodułu "sound.effects.echo". Musi on być
wywoływany używając jego pełnej nazwy.

   sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

Alternatywnym sposobem importowania podmodułu jest:

   from sound.effects import echo

To również spowoduje załadowanie podmodułu "echo" lecz udostępnia go
bez prefiksu pakietu, dzięki czemu można go użyć w następujący sposób:

   echo.echofilter(input, output, delay=0.7, atten=4)

Jeszcze innym sposobem jest bezpośredni import żądanej funkcji lub
zmiennej:

   from sound.effects.echo import echofilter

Ponownie, ładuje to podmoduł "echo", ale dzięki temu jego funkcja
"echofilter()" jest bezpośrednio dostępna:

   echofilter(input, output, delay=0.7, atten=4)

Zauważ, że podczas używania "from package import item", element może
być podmodułem (lub podpakietem) pakietu lub inną nazwą zdefiniowaną w
pakiecie, jak funkcją, klasą lub zmienną. Instrukcja "import" najpierw
sprawdza, czy element jest zdefiniowany w paczce; jeśli nie, zakłada,
że ​​jest to moduł i próbuje go załadować. Jeśli go nie znajdzie,
zgłaszany jest wyjątek "ImportError".

W przeciwieństwie do tego, gdy używana jest składnia  "import
item.subitem.subsubitem", każdy element oprócz ostatniego musi być
pakietem; ostatni element może być modułem lub pakietem, ale nie może
być klasą, funkcją lub zmienną zdefiniowaną w poprzednim elemencie.


6.4.1. Importowanie * z pakietu
-------------------------------

Teraz, co się dzieje, gdy użytkownik pisze "from sound.effects import
*"? W idealnym świecie, mamy nadzieję, że to w jakiś sposób wychodzi
do systemu plików, wyszukuje, które podmoduły są obecne w pakiecie i
importuje je wszystkie. Jednak może to zająć dużo czasu, a
importowanie modułów podrzędnych może mieć niepożądane skutki uboczne,
które powinny wystąpić tylko wtedy, gdy moduł podrzędny zostanie
jawnie zaimportowany.

Jedynym rozwiązaniem jest podanie przez autora pakietu jawnego indeksu
pakietu. Instrukcja "import" wykorzystuje następującą konwencję: jeśli
kod pakietu definiuje listę o nazwie "__all__", przyjmuje się, że jest
to lista nazw modułów, które powinny zostać zaimportowane, gdy
zostanie wywołane "from package import *". Do autora pakietu należy
aktualizowanie tej listy po wydaniu nowej wersji pakietu. Autorzy
pakietów mogą również zdecydować, że nie będą go wspierać, jeśli nie
widzą zastosowania do importowania * ze swojego pakietu. Na przykład
plik "sound/effects/__init__.py" może zawierać następujący kod:

   __all__ = ["echo", "surround", "reverse"]

To by znaczyło że "from sound.effects import *" zaimportuje trzy
wymienione podmoduły z pakietu "sound.effects".

Wróć uwagę na to, że podmoduły mogą być przysłaniane lokalnie
zdefiniowanymi nazwami. Na przykład, jeśli dodasz funkcję "reverse" do
pliku "sound/effects/__init__.py", instrukcja "from sound.effects
import *" zaimportuje tylko dwa podmoduły "echo" i "surround", ale nie
podmoduł "reverse", ponieważ jest on przysłonięty lokalnie
zdefiniowaną funkcją "reverse":

   __all__ = [
       "echo",      # odnosi się do pliku 'echo.py'
       "surround",  # odnosi się do 'surround.py'
       "reverse",   # !!! odnosi się teraz do funkcji 'reverse' !!!
   ]

   def reverse(msg: str):  # <-- ta nazwa przysłania submoduł 'reverse.py'
       return msg[::-1]    #     w przypadku 'from sound.effects import *'

Jeśli zmienna "__all__" nie jest zdefiniowana, instrukcja "from
sound.effects import *" *nie* importuje wszystkich podmodułów z
pakietu "sound.effects" do bieżącej przestrzeni nazw; upewnia się
tylko, że pakiet "sound.effects" został zaimportowany (ewentualnie
uruchamiając dowolny kod inicjujący w "__init__.py"), a następnie
importuje dowolne nazwy zdefiniowane w pakiecie. Obejmuje to wszelkie
nazwy zdefiniowane (i jawnie załadowane moduły podrzędne) przez
"__init__.py". Obejmuje również wszelkie podmoduły pakietu, które
zostały jawnie załadowane przez poprzednie instrukcje "import". Rozważ
ten kod:

   import sound.effects.echo
   import sound.effects.surround
   from sound.effects import *

W tym przykładzie moduły "echo" i "surround" są importowane do
bieżącej przestrzeni nazw, ponieważ są zdefiniowane w pakiecie
"sound.effects" podczas wykonywania instrukcji "from...import".
(Działa to również, gdy zmienna "__all__" jest zdefiniowana.)

Chociaż niektóre moduły są zaprojektowane do eksportowania tylko nazw
zgodnych z określonymi wzorcami podczas używania "import *", nadal
jest to uważane za złą praktykę w kodzie produkcyjnym.

Pamiętaj, nie ma nic złego w używaniu "from package import
specific_submodule"! W rzeczywistości jest to zalecana notacja, chyba
że moduł importujący musi używać podmodułów o tej samej nazwie z
innych pakietów.


6.4.2. Referencje wewnątrz-pakietowe
------------------------------------

Gdy pakiety są podzielone na podpakiety (jak w przypadku pakietu
"sound" w przykładzie), możesz użyć importu bezwzględnego, aby odnieść
się do podmodułów siostrzanych pakietów. Na przykład, jeśli moduł
"sound.filters.vocoder" musi użyć modułu "echo" w pakiecie
"sound.effects", może użyć "from sound.effects import echo".

Można również pisać importy względne w formie takiej: "from module
import name" instrukcji importu. Te importy wykorzystują wiodące
kropki do wskazania pakietów bieżących i nadrzędnych biorących udział
w imporcie względnym. Na przykład z modułu "surround" możesz użyć:

   from . import echo
   from .. import formats
   from ..filters import equalizer

Należy zauważyć, że importy względne są oparte na nazwie bieżącego
modułu. Ponieważ nazwa głównego modułu to zawsze ""__main__"", moduły
przeznaczone do użycia jako główny moduł aplikacji w Python-ie muszą
zawsze używać bezwzględnego importu.


6.4.3. Pakiety w wielu katalogach
---------------------------------

Packages support one more special attribute, "__path__".  This is
initialized to be a *sequence* of strings containing the name of the
directory holding the package's "__init__.py" before the code in that
file is executed.  This variable can be modified; doing so affects
future searches for modules and subpackages contained in the package.

Chociaż ta funkcja nie jest często potrzebna, można jej użyć do
rozszerzenia zestawu modułów znajdujących się w pakiecie.

-[ Przypisy ]-

[1] W rzeczywistości definicje funkcji są również „instrukcjami”,
    które są „wykonywane”; wykonanie definicji funkcji na poziomie
    modułu dodaje nazwę funkcji do globalnej przestrzeni nazw modułu.
