Moduły

Dowiedziałeś się, jak używać wielokrotnie fragmentu kodu programu dzięki funkcjom. A czego użyć, gdybyś chciał używać wielokrotnie paru funkcji w innych programach, które piszesz? Jak pewnie zgadłeś, odpowiedzią są moduły.

Są różne metody pisania modułów, ale najprościej jest stworzyć plik z rozszerzeniem .py, który będzie zawierał funkcje i zmienne.

Moduły można pisać nie tylko w Pythonie. Na przykład możesz napisać moduł do wydajnych obliczeń numerycznych w bardziej wydajnym języku C i po skompilowaniu używać go w swoim pythonowym kodzie.

Aby użyć zawartości modułu, należy go zaimportować. Dotyczy to również modułów ze standardowej biblioteki Pythona, od czego właśnie zaczniemy.

Przykład (zapisz jako module_using_sys.py):

import sys

print('The command line arguments are:')
for i in sys.argv:
    print(i)

print('\n\nThe PYTHONPATH is', sys.path, '\n')

Rezultat:

$ python module_using_sys.py we are arguments    # każdy agrument jest oddzielony spacją
The command line arguments are:
module_using_sys.py
we
are
arguments


The PYTHONPATH is ['/tmp/py',
# większość lini schowano
'/Library/Python/2.7/site-packages',
'/usr/local/lib/python2.7/site-packages']

PYTHONPATH to lista katalogów w których Python poszukuje modułów.

Jak to działa

Najpierw importujemy moduł sys używając wyrażenia import sys, czyli po prostu mówimy Pythonowi, że chcemy go używać. Moduł sys zawiera polecenia związane z Pythonem i jego środowiskiem, czyli systemem.

Podczas wykonywania wyrażenia import sys Python szuka pliku lub katalogu o odpowiedniej nazwie (m.in. zaczynającej się od sys). W tym przypadku to moduł wbudowany, więc Python wie gdzie go znaleźć.

Aby operacja się powiodła, moduł musi być w jednym z katalogów w zmiennej sys.path. Gdy moduł zostaje znaleziony, jego treść zostaje wykonana, a sam moduł staje się dostępny pod swoją nazwą. Inicjalizacja każdego modułu następuje tylko raz, podczas jego pierwszego użycia w danym programie.

Zmienna argv w module sys jest dostępna dzięki użyciu zapisu z kropką (sys.argv), dzięki czemu wiadomo, że ta nazwa jest częścią modułu sys. Zaletą tej notacji jest to, że programista na pierwszy rzut oka wie o która zmienną chodzi. Kolejną zaletą jest to, że możemy mieć wiele zmiennych argv w różnych modułach, i jednoznacznie się do niech odwoływać. Dzięki wykorzystaniu notacji z kropką, nazwa nie będzie się gryźć innymi zmiennymi.

Zmienna sys.argv jest listą ciągów znaków. (Listy poznamy dokładniej w następnym rozdziale). Dokładniej mówiąc, zawiera listę argumentów z którymi program został wywołany, czyli nazwę pliku zawierającego program oraz to co użytkownik programu wpisał po nazwie w wywołaniu z wiersza poleceń.

Jeżeli używasz IDE do pisania i uruchamiania tych programów, poszukaj w menu sposobu wpisywania argumentów linii komend.

Gdy wpisujemy python module_using_sys.py we are arguments, uruchamiamy moduł module_using_sys.py za pomocą aplikacji python wraz z argumentami we are arguments. Python przechowuje dla nas treść linii komend w zmiennej sys.argv.

Pamiętaj, że nazwa uruchamianego skryptu jest zawsze na początku listy sys.argv. Dlatego teraz mamy oznaczone: module_using_sys.py jako sys.argv[0], we jako sys.argv[1], are jako sys.argv[2] oraz arguments jako sys.argv[3]. Zauważ, że Python numeruje od 0, nie od 1.

sys.path zawiera listę katalogów, z których są importowane moduły. Zobacz, że pierwsza pozycja w sys.path jest pusta - ta pusta pozycja wskazuje że obecny katalog jest również częścią ścieżki sys.path która jest taka sama jak zmienna środowiskowa PYTHONPATH. To oznacza że możesz bezposrednio importować moduły znajdujace się w obecnym środowisku. W innym przypadku musiałbyś umieścić swój moduł w jednym z katalogów umieszczonych w sys.path.

Przy okazji, możesz w każdej chwili podejrzeć katalog, w którym jesteś wpisując w Pythonie import os; print(os.getcwd()).

Pliki pośrednie .pyc

Importowanie modułu to dosyć czasochłonna operacja, więc Python używa pewnych sztuczek, aby ją przyspieszyć. Jedną z nich jest tworzenie skompilowanych plików z rozszerzeniem .pyc, które są formą pośrednią przetwarzania programu (pamiętasz sekcję Wprowadzenie z opisem działania Pythona?). Taki plik .pyc jest przydatny, gdy masz zamiar zaimportować dany moduł po raz kolejny, używając innego programu — będzie o wiele szybciej, gdyż część pracy potrzebnej do zaimportowania została już wykonana. Poza tym, pliki .pyc są niezależne od platformy.

Uwaga
Pliki .pyc są zazwyczaj tworzone w tym samym folderze, co odpowiednie pliki .py. Jeżeli Python nie ma pozwolenia na zapis w tym folderze, pliki .pyc nie zostaną utworzone.

Konstrukcja from ... import ...

Jeżeli chcesz bezpośrednio zaimportować zmienną argv do swojego programu (aby nie pisać ciągle sys.), możesz użyć wyrażenia from sys import argv. Jeżeli chcesz zaimportować wszystko, co znajduje się w module sys, możesz użyć wyrażenia from sys import *. To działa z każdym modułem.

Przykład:

from math import sqrt
print("Square root of 16 is", sqrt(16))

Z reguły powinieneś używać formy import ..., a formy from...import... wtedy, gdy dana nazwa będzie używana bardzo często i kłopotliwe byłoby używanie pełnej ścieżki (powoduje to czasami zaśmiecenie przestrzeni nazw).

Identyfikacja modułu __name__

Każdy moduł posiada zmienną zawierającą jego nazwę (zazwyczaj). Najczęściej używa się tej zmiennej wtedy, gdy chcemy się dowiedzieć, czy moduł został zaimportowany, czy uruchomiony jako program. Jak już wcześniej wspomniano, gdy moduł zostaje zaimportowany po raz pierwszy, jego kod zostaje wykonany. Możemy tego użyć jeśli chcemy aby moduł zachowywał się w inny sposób w zależności od tego czy jest używany bezpośrednio czy importowany z innego modułu. To można osiągnąc używając atrybut __name__.

Przykład (zapisz jako module_using_name.py):

if __name__ == '__main__':
    print('This program is being run by itself')
else:
    print('I am being imported from another module')

Rezultat:

$ python module_using_name.py
This program is being run by itself

$ python
>>> import module_using_name
I am being imported from another module
>>>

Jak to działa

Każdy moduł Pythona ma zdefiniowaną własną nazwę. Jeżeli jest nią '__main__', oznacza to, że moduł działa samodzielnie, a wtedy możemy podjąć odpowiednie działania.

Tworzenie własnych modułów

Tworzenie własnych modułów jest proste, robisz to cały czas! A to dlatego, że każdy program w Pythonie jest także modułem. Ty musisz tylko zadbać, żeby miał rozszerzenie .py. Ten przykład powinien wszystko wyjaśnić.

Przykład (zapisz jako mymodule.py):

def say_hi():
    print('Hi, this is mymodule speaking.')

__version__ = '0.1'

Oto przykładowy moduł. Jak widać, nie ma tu nic szczególnie różniącego go od zwykłego programu w Pythonie. Następnie zobaczymy, jak go użyć w innych naszych programach.

Pamiętaj, że moduł powinien być umieszczony w tym samym katalogu co program, który z niego korzysta, lub też w jednym z katalogów wpisanych w sys.path.

Inny moduł (zapisz jako mymodule_demo.py):

import mymodule

mymodule.say_hi()
print('Version', mymodule.__version__)

Rezultat:

$ python mymodule_demo.py
Hi, this is mymodule speaking.
Version 0.1

Jak to działa

Zauważ, że używamy tego samego zapisu z kropkami przy uzyskiwaniu dostępu do elementów modułu. Python robi dobry użytek z tej samej notacji nadając temu swoisty „pythonowy” styl, dzięki czemu nie musimy wciąż poznawać coraz to nowych metod pracy.

Oto wersja z użyciem from...import... (zapisz jako mymodule_demo2.py):

from mymodule import say_hi, __version__

say_hi()
print('Version', __version__)

Rezultat mymodule_demo2.py jest taki sam jak mymodule_demo.py.

Zauważ, że jeżeli nazwa __version__ już istniała wcześniej w module, który importuje mymodule, powstaną zgrzyty. Szczególnie że powszechne jest zjawisko podawania wersji modułu właśnie za pomocą tej nazwy. Stąd zawsze lepiej użyć wyrażenia import, nawet gdy miałoby to wydłużyć program.

Możesz także użyć:

from mymodule import *

To spowoduje zaimportowanie prawie wszystkich nazw, jak na przykład say_hi, ale ominie __version__, gdyż zaczyna się ona od podwójnego podkreślenia.

Uwaga: Pamiętaj aby unikać importowania za pomocą gwiazdki tzn. from mymodule import *.

Zen Pythona

Jednym z głównych zasad w Pythonie jest "Wyrażone wprost jest lepsze niż domniemane.". Uruchom import this aby dowiedzieć się więcej.

Funkcja dir

Możesz użyć wbudowanej funkcji dir, aby wypisać identyfikatory zdefiniowane przez dany obiekt. Na przykład w module identyfikatorami są funkcje, klasy i zmienne w nim zadeklarowane.

Kiedy dołożysz nazwę modułu do dir(), zwróci ona listę nazw zawartych w podanym module. Gdy nie zostanie podany argument, zwrócona zostanie lista nazw zdefiniowanych w aktualnym module.

Przykład:

$ python
>>> import sys

# wyświetl nazwy atrybutów w module sys
>>> dir(sys)
['__displayhook__', '__doc__',
'argv', 'builtin_module_names',
'version', 'version_info']
# tylko kilka lini tu pokazano

# wyświetl nazwy atrybutów dla obecnego modułu
>>> dir()
['__builtins__', '__doc__',
'__name__', '__package__', 'sys']

# stwórz nową zmienną 'a'
>>> a = 5

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'sys', 'a']

# usuń zmienną a
>>> del a

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'sys']

Jak to działa

Na początku sprawdzamy działanie dir na zaimportowanym module sys. Widać ogromną listę atrybutów, które zawiera.

Następnie używamy funkcji dir bez parametrów. Domyślnie zwraca ona listę atrybutów aktualnego modułu. Zauważ, że lista zaimportowanych modułów jest też częścią wyniku.

W celu ujrzenia dir w akcji, deklarujmy nową zmienną a, przypisujemy jej wartość, a następnie sprawdzamy, że na liście pojawiła nazwa naszej nowej zmiennej. Usuwamy ją poleceniem del, czego efekt widać po kolejnym użyciu dir.

Uwaga do del — to polecenie usuwa zmienną/nazwę (w tym wypadku del a), dzięki czemu później nie da się odnieść do tej nazwy, tak jakby nigdy wcześniej nie istniała.

Pamiętaj, że funkcja dir działa z każdym obiektem. Na przykład możesz napisać dir(str), aby poznać atrybuty klasy str (string).

Istnieje również funkcja vars(), która potancjalnie zwróci atrybuty i ich wartości, ale nie będzie działać w każdym przypadku.

Paczki

Właśnie zacząłeś dogłębnie poznawać hierarchię elementów twoich programów. Zmienne zazwyczaj znajdują się w funkcjach. Funkcje oraz zmienne globalne — w modułach. A co gdy chcesz zarządzać modułami? W tym miejscu na scenę wkraczają paczki.

Paczki to katalogi z modułami oraz ze specjalnym plikiem __init__.py, który informuje Pythona, że ten katalog jest specjalnie przeznaczony właśnie do przechowywania modułów.

Powiedzmy, że chcesz stworzyć paczkę o nazwie swiat zawierającą paczki azja, afryka itd., zaś w nich na przykład indie czy madagaskar.

Oto, jak powinna wyglądać twoja struktura katalogów:

- <jakiś katalog wymieniony w sys.path>/
    - swiat/
        - __init__.py
        - azja/
            - __init__.py
            - indie/
                - __init__.py
                - foo.py
        - afryka/
            - __init__.py
            - madagaskar/
                - __init__.py
                - bar.py

Paczki są wygodnym sposobem segregacji modułów. Zobaczysz wiele przykładów ich użycia w bibliotece standardowej.

Podsumowanie

Tak jak funkcje są częściami programu wielokrotnego użytku, tak moduły to programy wielokrotnego użytku. Paczki są odrębną hierarchią organizacji modułów. Standardowa biblioteka Pythona jest przykładem zestawu paczek i modułów.

Zobaczyliśmy, jak użyć tych modułów i utworzyć swoje własne.

Następnie poznamy pewne interesujące koncepty zwane strukturami danych.

results matching ""

    No results matching ""