Podsekcje

 
6. Moduły

W chwili gdy zakończy się pracę w interpreterze Pythona i ponownie rozpocznie, wszystkie definicje, które wprowadzono (funkcje i zmienne) zostają stracone. Dlatego też, jeśli chce się napisać ździebko dłuższy program, lepiej będzie gdy użyje się edytora tekstów do przygotowania poleceń dla interpretera i uruchomi go z przygotowanym plikiem na wejściu. Nazywa się to tworzeniem skryptu6.1W miarę,, jak twój program staje się dłuższy, zajdzie konieczność podzielenia go na kilka plików w celu łatwiejszej pielęgnacji 6.2 całości. Będziesz chciał również użyć funkcji, które właśnie napisałeś w paru innych programach bez potrzeby wklejania ich w każdy program z osobna.

Python wspomoże te działania poprzez pewien sprytny mechanizm umieszczania definicji w pliku i używania ich w skrypcie lub w interaktywnej postaci interpretera. Taki plik nazywany jest modułem: definicje z modułu mogą być importowane do innych modułów lub do głównego modułu (zestaw zmiennych, których używałeś w skrypcie wykonywanym na najwyższym poziomie i w trybie kalkulatora).

Moduł jest plikiem zawierającym definicje Pythona i jego instrukcje. Nazwa pliku jest nazwą modułu pozbawionego rozszerzenia .py. W module, nazwa modułu dostępna jest jako wartość zmiennej globalnej __name__. Na przykład, użyj swojego ulubionego edytora tekstów6.3 i stwórz plik o nazwie fibo.py. Umieść go w bieżącym katalogu z następującą zawartością:

# Moduł liczb Fibonacciego

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

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

Teraz, po uruchomieniu interpretera Pythona można zaimportować ten moduł za pomocą następującego polecenia:

>>> import fibo

W ten sposób nie zaimportuje się nazw funkcji zdefiniowanych w module fibo wprost do bieżącej tablicy symboli: to polecenie wprowadza tylko nazwę fibo do tej tablicy. Aby dostać się do owych funkcji, trzeba użyć nazwy modułu:

>>> fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
Jeżeli chce się używać funkcji często, można przypisać jej lokalną nazwę:

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

 
6.1 Ciąg dalszy o modułach

Moduł może zawierać instrukcje wykonywalne obok definicji funkcji. Instrukcje te mają na celu inicjalizację modułu. Wykonywane są tylko w chwili importowania modułu po raz pierwszy, gdzieś w programie.6.4

Każdy z modułów posiada swoją prywatną tablicę symboli, która używana jest przez wszystkie funkcje zdefiniowane w module jako globalna tablica symboli. W ten sposób, autor modułu może używać w nim zmiennych globalnych bez konieczności martwienia się o przypadkowy konflikt nazwy występującej w module z nazwą globalną zdefiniowaną w programie użytkownika. Z drugiej jednak strony, jeżeli wiesz co robisz, można wpłynąć na globalną zmienną modułu za pomocą takiej samej notacji, jakiej użyliśmy poprzednio, aby użyć wprost nazwy funkcji z modułu: nazwa_modulu.nazwa_elementu.

Moduły mogą importować inne moduły. Zazwyczaj, acz nie jest to wymagane, wszystkie instrukcje import umieszczane są na początku modułu (lub skryptu). Nazwy zaimportowanych modułów umieszczane są w globalnej tablicy symboli importujących modułów.

Istnieje wariant instrukcji import, która importuje nazwy z modułu wprost do tablicy symboli modułów importujących. Na przykład:

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

Ta konstrukcja nie wprowadza nazwy modułu, z którego importujemy, do lokalnej tablicy symboli (tak więc, w tym przykładzie fibo nie jest zdefiniowane).

Jest też pewien wariant, który importuje wszystkie nazwy z modułu:

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

Ten mechanizm pozwala zaimportować wszystkie nazwy z wyjątkiem tych, które zaczynają się od znaku podkreślenia (_).

 
6.1.1 Ścieżka poszukiwań modułów

 Gdy moduł o nazwie pomyje jest importowany, interpreter poszukuje pliku o nazwie pomyje.py w bieżącym katalogu, następnie w katalogach określonych przez zmienną systemową PYTHONPATH. Zmienna ta ma taką samą składnię co zmienna PATH, tzn. jest listą katalogów. W przypadku, gdy PYTHONPATH nie jest określona, lub gdy plik nie jest znaleziony w katalogach tam wymienionych, poszukiwanie kontynuowane jest na ścieżkach ustawionych w momencie instalacji: na jest to zazwyczaj .:/usr/local/lib/python.

Na samym końcu, moduły poszukiwane są na liście katalogów umieszczonych w zmiennej pythonowej sys.path, która inicjalizowana jest nazwami katalogu zawierającego skrypt wejściowy (lub z bieżącego katalogu), zawartością zmiennej PYTHONPATH i domyślnymi katalogami instalacyjnymi. W ten sposób zmyślne programy w Pythonie mogą modyfikować a nawet zastępować ścieżkę poszukiwań modułów. Zobacz później podrozdział na temat standardowych modułów.

6.1.2 Skompilowane pliki Pythona

Ważnym czynnikiem przyspieszenia rozruchu dla małych programów, które używają mnóstwo standardowych modułów jest obecność pliku pomyje.pyc. W pliku tym zawarta jest skompilowana już ,,bajt-kodowa''6.5wersja modułu spam. Czas modyfikacji wersji pliku pomyje.py, z którego powstał pomyje.pyc, jest zarejestrowany w tymże ostatnim. Plik .pyc jest ignorowany, jeżeli oba te czasy nie pasują do siebie6.6

W normalnych warunkach, nie trzeba zrobić nic szczególnego, aby utworzyć plik pomyje.pyc. Kiedykolwiek pomyje.py zostało pomyślnie skompilowane, interpreter usiłuje zapisać skompilowana wersję do pomyje.pyc. Nie ma błędu, jeśli zapis się nie powiedzie. Jeżeli z jakiegokolwiek powodu plik ten nie został zapisany, to pomyje.pyc zostanie rozpoznane jako niepoprawny i zignorowany. Zawartość pomyje.pyc jest niezależna od platformy, tak więc katalog modułów może być dzielony pomiędzy maszynami o różnej architekturze.6.7

Parę wskazówek dla ekspertów:

 
6.2 Moduły standardowe

Python dostarczany jest z biblioteką standardowych modułów, które opisane są w osobnym dokumencie: Opis biblioteki Pythona (inaczej «Opis biblioteki»). Niektóre moduły wbudowane są w interpreter: są one źródłem tych operacji, które nie są częścią jądra6.8 języka, lecz pomimo tego zostały wbudowane albo z powodu wydajności, lub aby wprowadzić dostęp do podstawowych operacji systemu operacyjnego, np. funkcje systemowe. To co zostało wbudowane w interpreter, jest kwestią opcji instalacji, tzn. moduł ameba dostarczany jest tylko na te systemy, które w pewien sposób wspomagają podstawowe operacje Ameby. Jeden z modułów wbudowanych zasługuje na szczególną uwagę: sys , który jest wbudowany w niemal każdy interpreter Pythona. Zmienne sys.ps1 i sys.ps2 definiują napisy używane jako pierwszy i drugi znak zachęty:

>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print 'Yuck!'
Yuck!
C>

Zmienne te dostępne są tylko w trybie interakcyjnym interpretera.

Zmienna sys.path jest listą napisów, które decydują o ścieżce poszukiwań modułów przez interpreter. Domyślnie inicjowane są zawartością zmiennej systemowej PYTHONPATH lub wbudowanymi domyślnymi katalogami poszukiwań, jeśli PYTHONPATH nie istnieje. Można modyfikować sys.path poprzez standardowe operacje na listach:

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

 
6.3 Funkcja dir()

Funkcja wbudowana dir() służy do znajdywania wszystkich nazw, które są zdefiniowane w module. Zwraca ona posortowaną listę napisów:

>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__name__', 'argv', 'builtin_module_names', 'copyright', 'exit',
'maxint', 'modules', 'path', 'ps1', 'ps2', 'setprofile', 'settrace',
'stderr', 'stdin', 'stdout', 'version']

Wywołana bez argumentów dir() zwróci listę nazw, które właśnie zdefiniowałeś:

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

Zauważ, że zwrócona została lista wszystkich typów nazw: zmiennych, modułów, funkcji, itd.

dir() nie poda listy nazw funkcji i zmiennych wbudowanych. Jeśli chce się uzyskać taką listę, to posłuż się standardowym modułem __builtin__ :

>>> import __builtin__
>>> dir(__builtin__)
['AccessError', 'AttributeError', 'ConflictError', 'EOFError', 'IOError',
'ImportError', 'IndexError', 'KeyError', 'KeyboardInterrupt',
'MemoryError', 'NameError', 'None', 'OverflowError', 'RuntimeError',
'SyntaxError', 'SystemError', 'SystemExit', 'TypeError', 'ValueError',
'ZeroDivisionError', '__name__', 'abs', 'apply', 'chr', 'cmp', 'coerce',
'compile', 'dir', 'divmod', 'eval', 'execfile', 'filter', 'float',
'getattr', 'hasattr', 'hash', 'hex', 'id', 'input', 'int', 'len', 'long',
'map', 'max', 'min', 'oct', 'open', 'ord', 'pow', 'range', 'raw_input',
'reduce', 'reload', 'repr', 'round', 'setattr', 'str', 'type', 'xrange']

 
6.4 Pakiety

Pakiety są sposobem na ,,ustrukturalnienie'' przestrzeni nazw modułów Pythona poprzez używanie ,,kropkowanych nazw modułów''. Na przykład, nazwa modułu A.B oznacza moduł składowy "B" pakietu "A". Tak samo jak używanie modułów zaoszczędza autorom różnych modułów martwienia się o konflikt nazw globalnych, tak samo używanie kropkowanych nazw modułów zaoszczędza autorom wielomodułowych pakietów jak NumPy lub Python Imaging Library martwienia się nazwy swoich modułów.

Załóżmy, że chce się zaprojektować zbiór modułów (,,pakiet'') służący do jednolitej obsługi plików i danych dźwiękowych. Istnieje mnóstwo formatów zapisu dźwięku (zwykle rozpoznawane po rozszerzeniu plików, np. .wav, .aiff, .au), co spowoduje, że może będziesz musiał stworzyć i utrzymywać zwiększającą się kolekcję modułów konwersji pomiędzy różnymi formatami plików. Jest również dużo różnych operacji, które można przeprowadzić na danych dźwiękowych (np. miksowanie, dodawanie pogłosu, zastosowanie funkcji equalizera, tworzenie sztucznego efektu stereo), tak więc, kończąc już, będziesz pisał niekończący się strumień modułów do wykonywania tych operacji. Poniżej przedstawiono jedną z możliwych struktur takiego pakietu (wyrażona ona jest w postaci hierarchicznego drzewa, na podobieństwo systemu plików):

Sound/                          Pakiet szczytowy
      __init__.py               Inicjalizacja pakietu do obsługi dźwięku
      Formats/                  Moduły składowe do konwersji plików
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      Effects/                  Pakiet składowy z efektami dźwiękowymi
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      Filters/                  Pakiet składowy z operacjami filtrowania
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...
Plik __init__.py są wymagane, aby zmusić Pythona do traktowania katalogów jako zawierające pakiety. Jest to konieczne, aby uchronić katalogi z powszechnie spotykanymi nazwami, takie jak "string", od niezamierzonego ukrycia poprawnych modułów, które pojawią się później na ścieżce poszukiwań modułów. W najprostszym przypadku, plik __init__.py może być pustym plikiem, ale może też zawierać pewien kod do wykonania, lub ustawiać wartość zmiennej __all__, opisaną później.

Użytkownicy tego pakietu mogą importować poszczególne moduły, np.:

import Sound.Effects.echo
To spowoduje załadowanie modułu składowego Sound.Effects.echo. Później, trzeba używać go za pomocą pełnej nazwy, tzn.

Sound.Effects.echo.echofilter(input, output, delay=0.7, atten=4)
Alternatywnym sposobem importowania modułu składowego jest:

from Sound.Effects import echo
W ten sposób również załadujemy moduł składowy echo ale sprawimy, że dostępny jest z nazwą niezawierającą nazwy pakietu rodzicielskiego:

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

Inną wariacją na ten temat jest zaimportowanie wprost żądanej funkcji:

from Sound.Effects.echo import echofilter

W ten sposób ponownie ładujemy moduł składowy echo, lecz jego funkcja echofilter() jest dostępna wprost:

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

Zauważ, że kiedy używa się from pakiet import element, element może być modułem składowym (lub pakietem składowym) lub inną nazwą zdefiniowaną dla tego pakietu,, jak funkcja, klasa czy zmienna. Instrukcja import najpierw sprawdza, czy element jest zdefiniowany w pakiecie; jeśli nie, zakłada się, że jest to moduł i poczynione są starania o jego załadowanie. Jeśli nie zostanie on znaleziony, zgłaszany jest wyjątek ImportError.

W przeciwieństwie do tego, jeśli używa się składni import element.element_skladowy.kolejny_element_skladowy, każdy element z wyjątkiem ostatniego musi być pakietem: ostatni element może być modułem lub pakietem ale nie klasą, funkcją lub zmienną zdefiniowaną w poprzednim elemencie.

 
6.4.1 Importowanie * z pakietu

A teraz, co się stanie, kiedy użytkownicy napiszą from Sound.Effects import *? Ktoś mógłby pomyśleć naiwnie, że ta instrukcja w jakiś sposób wychodzi do systemu plików, znajduje wszystkie pliki z modułami składowymi, które są obecne w pakiecie-katalogu i wszystkie je importuje. Niestety, taka operacja nie działa zbyt dobrze na macintosh'ach i w Windows, gdzie system plików nie zawsze wyposażony jest w dokładną informację na temat wielkości liter w nazwach!6.9Na tych platformach nie ma sposobu dowiedzenia się, czy plik ECHO.PY powien być zaimportowany jako moduł echo, Echo czy ECHO (np. Windows 95 ma denerwujący zwyczaj pokazywania nazw plików z pierwszą dużą literą). Ograniczenie DOS-a (8+3 znaki na nazwę pliku) dodaje jeszcze jeden interesujący problem do tej listy jeżeli chodzi o długie nazwy modułów.

Jedynym wyjściem dla autora takiego pakietu jest dostarczenie wprost indeksu jego części składowych. Instrukcja importu posługuje się następującą konwencją: jeżeli kod pakietu __init__.py zdefiniuje listę o nazwie __all__, to przyjmuje się, że zawiera ona nazwy wszystkich modułów importowanych za pomocą instrukcji from pakiet import *. Zadaniem autora pakietu jest utrzymywanie stanu tej listy na bieżąco, w chwili gdy wypuszczane są nowe wersje pakietu. Autorzy pakietów mogą również nie dostarczać tej listy, jeśli nie widzą sensu z importowania * z ich pakietu. Na przykład plik Sound/Effects/__init__.py mógłby zawierać następujący kod:

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

Znaczyłoby to, że from Sound.Effects import * zaimportuje trzy moduły składowe z pakietu Sound.

Jeśli __all__ nie jest zdefinowana, instrukcja from Sound.Effects import * nie zaimportuje wszystkich modułów składowych z pakietu Sound.Effects do bieżącej przestrzeni nazw: upewni się tylko, czy pakiet Sound.Effects został zaimportowany (z możliwym wykonaniem kodu z pliku __init__.py) a potem zaimportuje wszystkie nazwy zdefiniowane w tym pakiecie. Wchodzą w nie nazwy zdefiniowane (i moduły składowe załadowane wprost) w pliku __init__.py oraz moduły składowe pakietu załadowane wprost przez poprzednie instrukcje importu, tzn.

import Sound.Effects.echo
import Sound.Effects.surround
from Sound.Effects import *

W tym przykładzie moduły echo i sorround importowane są do bieżącej przestrzeni nazw ponieważ są zdefiniowane w pakiecie Sound.Effects, gdy wykonywany jest from...import (działa to również, gdy zdefiniowano __all__).

Trzeba tu zauważyć, że stosowanie importowania * z modułu lub pakietu idzie powoli w odstawkę, ponieważ często powoduje nieczytelny kod. Jest oczywiście w porządku, gdy stosuje się tę formułę, aby zaoszczędzić trochę na klepaniu klawiszami w trybie interaktywnym i gdy pewne moduły są zaprojektowane tak, że eksportują tylko nazwy odpowiadające pewnym schematom.

Trzeba pamiętać, że nie ma nic złego w używaniu formuły from Pakiet import pewien_modul! Właściwie, ta notacja jest zalecana, chyba że moduł importujący używa modułów składowych o takiej samej nazwie z paru różnych pakietów.

6.4.2 Odniesienia pomiędzy pakietami

Często zachodzi wymóg odniesienia się jednego modułu do drugiego. Na przykład, moduł sorround może używać modułu echo. W rzeczywistości, jest to tak często spotykane, że instrukcja import poszukuje najpierw w zawierającym ją pakiecie, zanim przejdzie na standardową ścieżkę poszukiwań. Tak więc, moduł sorround może użyć zwykłego import echo lub from echo import echofilter. Jeśli importowany moduł nie zostanie znaleziony w bieżącym pakiecie (w którym bieżący moduł jest modułem składowym), instrukcja import szuka w szczytowym module o podanej nazwie.

Kiedy pakiety posiadają składowe pakiety (tak jak Sound w naszym przykładzie), nie istnieje skrót, aby odnieść się do modułu składowego pakietów składowych -- trzeba użyć pełnej nazwy pakietu składowego. Na przykład, jeśli moduł Sound.Filters.vocoder musi użyć modułu echo z pakietu Sound.Effects, może zastosować from Sound.Effects import echo.



...skryptu6.1
To czy nazwa skrypt brzmi mniej poważnie od nazwy program jest sprawą gustu...
... pielęgnacji6.2
ang. maintenance
... tekstów6.3
Nieśmiertelne «favorite text editor»...
... programie.6.4
Tak naprawdę, definicja funkcji jest także ,,instrukcją'', która jest ,,wykonywana''. Wykonanie to powoduje wprowadzenie nazwy funkcji do globalnej tablicy symboli modułu.
... ,,bajt-kodowa''6.5
ang. byte-coded
... siebie6.6
Innymi słowy: używany jest .pyc jeśli data modyfikacji .py jest wcześniejsza od daty modyfikacji .pyc
... architekturze.6.7
Zazwyczaj wersje interpretera muszą być tes same
... jądra6.8
ang. core
... nazwach!6.9
Ten wykrzyknik powinien się tu pojawić!
Zajrzyj do Informacji na temat tej publikacji... aby pomóc w jej rozwoju.