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ą:

# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to 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('Yuck!')
Yuck!
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/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

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

The __init__.py files are required to make Python treat directories containing the file as packages (unless using a namespace package, a relatively advanced feature). This prevents directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable, described later.

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ć przykrywane 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łu reverse, ponieważ jest on przykryty lokalnie zdefiniowaną funkcją reverse:

__all__ = [
    "echo",      # refers to the 'echo.py' file
    "surround",  # refers to the 'surround.py' file
    "reverse",   # !!! refers to the 'reverse' function now !!!
]

def reverse(msg: str):  # <-- this name shadows the 'reverse.py' submodule
    return msg[::-1]    #     in the case of a '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

Pakiety obsługują jeszcze jeden specjalny atrybut, __path__. Jest to inicjalizowane jako lista zawierająca nazwę katalogu zawierającego __init__.py przed wykonaniem kodu w tym pliku. Ta zmienna może być modyfikowana; ma to wpływ na przyszłe wyszukiwania modułów i podpakietów zawartych w pakiecie.

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

Przypisy