PPy3/Moduły: Różnice pomiędzy wersjami
Linia 71: | Linia 71: | ||
Korzystając z modułów biblioteki standardowej warto nieco uważać na możliwość konfliktów nazw; nie należy np. własnemu programowi lub modułowi nadawać nazwy identycznej z nazwą któregoś z modułów standardowych, z którego zamierzamy skorzystać w ramach danego projektu - dla instrukcji <tt>import</tt> moduł własny programisty ma pierwszeństwo, i w efekcie moduł własny ,,przesłoni" standardowy. Ale na wszelki wypadek lepiej jest unikać wszystkich nazw modułów standardowych (a nuż w trakcie rozwoju naszego projektu postanowimy wykorzystać w nim kolejne moduły standardowe?). | Korzystając z modułów biblioteki standardowej warto nieco uważać na możliwość konfliktów nazw; nie należy np. własnemu programowi lub modułowi nadawać nazwy identycznej z nazwą któregoś z modułów standardowych, z którego zamierzamy skorzystać w ramach danego projektu - dla instrukcji <tt>import</tt> moduł własny programisty ma pierwszeństwo, i w efekcie moduł własny ,,przesłoni" standardowy. Ale na wszelki wypadek lepiej jest unikać wszystkich nazw modułów standardowych (a nuż w trakcie rozwoju naszego projektu postanowimy wykorzystać w nim kolejne moduły standardowe?). | ||
+ | |||
+ | ==Funkcja <tt>dir</tt>== | ||
+ | |||
+ | Funkcję <tt>dir</tt> można wykorzystać do zbadania zawartości modułu: | ||
+ | <source lang=python> | ||
+ | In [1]: import witaj | ||
+ | |||
+ | In [2]: dir(witaj) | ||
+ | Out[2]: | ||
+ | ['__builtins__', | ||
+ | '__cached__', | ||
+ | '__doc__', | ||
+ | '__file__', | ||
+ | '__loader__', | ||
+ | '__name__', | ||
+ | '__package__', | ||
+ | '__spec__', | ||
+ | 'witaj'] | ||
+ | </source> | ||
+ | |||
+ | Wynikiem jest lista nazw zdefiniowanych w podanym module. Nazwy otoczone znakami podkreślenia (podwójnymi) mają specjalne znaczenie i powstają ,,automatycznie"; nie powinniśmy sami definiować nazw o zbliżonym kształcie - chyba że świadomie, i wiedząc dokładnie co chcemy tym osiągnąć. | ||
+ | |||
+ | ==Jestem modułem, czy programem?== | ||
+ | |||
+ | Nazwa <tt>__name__</tt> w module jest dość przydatna. Ponieważ każdy plik o nazwie kończącej się na <tt>.py</tt> może pełnić zarówno rolę modułu, jak i programu wykonywalnego (,,głównego"), to dobrze jest, aby w kodzie zawartym w tym pliku można było rozpoznać, w jakiej roli został on uruchomiony. Jeżeli plik wykorzystywany jest w charakterze modułu, tj. poprzez instrukcję <tt>import</tt>, to: | ||
+ | <source lang=python> | ||
+ | In [4]: witaj.__name__ == 'witaj' | ||
+ | Out[4]: True | ||
+ | </source> | ||
+ | |||
+ | czyli pod nazwą <tt>__name__</tt> kryje się napis, będący nazwą modułu. Jeżeli jednak plik został uruchomiony w charakterze programu głównego, to treścią tej nazwy będzie napis <tt>'__main__'</tt>. Jest szeroko przyjętą praktyką umieszczania poleceń, które mają być wykonywane tylko w przypadku, gdy plik zostanie uruchomiony jako program główny, wewnątrz instrukcji <tt>if</tt>: | ||
+ | <source lang=python> | ||
+ | (...) | ||
+ | |||
+ | if __name__ == '__main__': | ||
+ | # blok instrukcji uruchamiających program | ||
+ | |||
+ | </source> | ||
+ | |||
+ | Pozwala to na wykorzystywanie tego samego pliku w obu rolach: programu głównego, i modułu. | ||
+ | |||
=Ćwiczenia= | =Ćwiczenia= |
Wersja z 13:53, 3 sie 2016
Spis treści
Moduły i biblioteki
Wspomnieliśmy wcześniej, że problemu raz rozwiązanego nie warto rozwiązywać po raz drugi, trzeci, ... (no chyba, że mamy pomysł na jakieś jakościowo nowe rozwiązanie). Zgodnie z tą zasadą, kod stanowiący rozwiązanie opakowuje się w funkcję - z której następnie można korzystać wielokrotnie. Ale na razie wiemy tylko, że z funkcji możemy korzystać w obrębie programu, w którym występuje definicja tejże funkcji. A co z innymi programami? Metoda kopiuj/wklej to nie jest najlepszy pomysł - wyobraźmy sobie chociaż, że w kodzie funkcji wykryliśmy drobny błąd (albo możliwość istotnego ulepszenia); będziemy teraz wyszukiwać wszystkich programów, w których ten kod uprzednio wkleiliśmy, aby je skorygować? Zamiast tego, lepiej jest skorzystać z stworzonego dokładnie w tym celu mechanizmu modułów - plików, w których umieszczamy definicje funkcji (i ewentualnie innych obiektów), z których będzie można korzystać w wielu różnych programach.
Ułatwienie wielokrotnego użytku kodu nie jest jedyną korzyścią z dzielenia kodu programu na funkcje. Warto to robić również, gdy wielokrotnego użytku się nie przewiduje - o ile zadanie do wykonania przez program nie jest trywialne proste, a kod je realizujący bardzo krótki. Wprowadzenie do kodu pewnej struktury wynikającej z podziału różnych elementów algorytmu pomiędzy funkcje sprzyja czytelności programu i ułatwia jego ewentualną modyfikację w przyszłości.
Najprostszy moduł
Jako moduł może służyć dowolny plik zawierający kod w Pythonie, opatrzony nazwą z końcówką .py (tutaj nazwa ma znaczenie). Zazwyczaj w module umieszcza się jedynie definicje (funkcji, klas, ewent. stałych nazwanych), a nie - kod faktycznie wykonywany.
Nazwijmy plik o poniższej treści witaj.py:
#! /usr/bin/python3
def witaj(imie):
print('Witaj {}!'.format(imie))
Wykorzystaliśmy tu znaną już nam metodę format do zgrabnego wstawienia imienia do treści powitania. Ten sam skutek dałoby się osiągnąć stosując operację sklejania napisów:
print('Witaj ' + imie + '!')
użycie formatowania jednak jest zalecane, zwłaszcza w bardziej złożonych przypadkach.
Uruchomienie pliku witaj.py jako programu nie spowoduje żadnego widocznego skutku - funkcja witaj zostanie wprawdzie zdefiniowana, ale program zakończy działanie zanim zostanie ona w ogóle użyta (wywołana). Chcąc wykorzystać tę funkcję w oddzielnym programie, musimy najpierw w kodzie tego programu wskazać, gdzie znajduje się definicja tej funkcji. Do tego służy polecenie import:
#! /usr/bin/python3
import witaj
witaj.witaj('Heleno')
Notacja witaj.witaj w tym przypadku wskazuje, że chodzi o funkcję witaj (słowo po kropce) z modułu o nazwie witaj (to przed kropką). Oczywiście nazwy te równie dobrze mogą brzmieć różnie, a w jednym module można zdefiniować wiele funkcji. Polecenie import witaj nadaje, w ramach tego programu, znaczenie nazwie witaj - będzie ona oznaczać moduł, którego zawartością (elementami) są funkcje (i ew. inne obiekty) zdefiniowane w pliku witaj.py.
Można również inaczej:
#! /usr/bin/python3
from witaj import witaj
witaj('Heleno')
Przy tej postaci instrukcji import, udostępniona w ramach programu zostaje tylko funkcja witaj i należy się do niej odwoływać przez ,,gołą" nazwę. Obiektów importowanych z modułu o nazwie wskazanej po słowie from może być więcej, należy podać ich nazwy po słowie import, oddzielone przecinkami.
Można też jeszcze inaczej:
#! /usr/bin/python3
from witaj import *
witaj('Jakubie')
Taka instrukcja poleca udostępnić wszystkie nazwy, jakie zostały zdefiniowane w module witaj. W tym akurat przypadku jest tylko jedna taka nazwa, nie dzieje się więc nic innego niż w poprzednim przykładzie. Jeżeli jednak moduł witaj zostanie w przyszłości wzbogacony o dalsze definicje, to używając instrukcji import z gwiazdką jak powyżej, będziemy te definicje importować do swojego programu zupełnie nieświadomie; nie będzie w tym nic złego, dopóki się nie okaże np. że nazwa któregoś z obiektów zdefiniowanych w tym module pokrywa się z jakąś nazwą występującą w bibliotece standardowej, i to nazwą obiektu, z jakiego postanowiliśmy również skorzystać w naszym kodzie - może się wtedy zdarzyć, że będziemy wywoływać wcale nie tę funkcję, o którą nam chodziło... Więcej o możliwych konfliktach nazw powiemy dalej, na dziś warto zapamiętać: instrukcja from ... import * nie powinna występować w ostatecznej wersji kodu żadnego programu (nie ma nic złego w używaniu jej np. przy interakcyjnym testowaniu działania funkcji z danego modułu, itp.).
Instrukcja import we wszystkich jej wersjach jest instrukcją Pythona jak każda inna; można ją np. wywoływać warunkowo (wewnątrz instrukcji if, czy też wewnątrz definicji funkcji - w takim przypadku, nazwy zaimportowane mają zasięg jedynie lokalny, ograniczony do wnętrza funkcji, podobnie jak zmienne lokalne, wprowadzone wewnątrz definicji funkcji.
Biblioteka standardowa
Domyślna instalacja środowiska Python jest od razu zaopatrzona w dość bogatą kolekcję gotowych modułów, zawierających rozwiązania problemów już dawno rozwiązanych i często przydatne programiście. Biblioteka standardowa jest doskonale udokumentowana - wystarczy zajrzeć tutaj, i powielanie tej dokumentacji nie miałoby sensu - przykłady zastosowań zobaczymy wkrótce.
Niekiedy rozwiązanie jakiegoś problemu wymaga sięgnięcia do kodu na ,,niższym poziomie" niż Python, np. w języku C (lub też może być to po prostu opłacalne ze względów wydajnościowych). Biblioteka standardowa zawiera również i takie moduły, obok modułów, których zawartością jest kod w Pythonie. Moduły takie można też tworzyć samodzielnie, ale jest to temat spoza zakresu tego kursu.
Korzystając z modułów biblioteki standardowej warto nieco uważać na możliwość konfliktów nazw; nie należy np. własnemu programowi lub modułowi nadawać nazwy identycznej z nazwą któregoś z modułów standardowych, z którego zamierzamy skorzystać w ramach danego projektu - dla instrukcji import moduł własny programisty ma pierwszeństwo, i w efekcie moduł własny ,,przesłoni" standardowy. Ale na wszelki wypadek lepiej jest unikać wszystkich nazw modułów standardowych (a nuż w trakcie rozwoju naszego projektu postanowimy wykorzystać w nim kolejne moduły standardowe?).
Funkcja dir
Funkcję dir można wykorzystać do zbadania zawartości modułu:
In [1]: import witaj
In [2]: dir(witaj)
Out[2]:
['__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'witaj']
Wynikiem jest lista nazw zdefiniowanych w podanym module. Nazwy otoczone znakami podkreślenia (podwójnymi) mają specjalne znaczenie i powstają ,,automatycznie"; nie powinniśmy sami definiować nazw o zbliżonym kształcie - chyba że świadomie, i wiedząc dokładnie co chcemy tym osiągnąć.
Jestem modułem, czy programem?
Nazwa __name__ w module jest dość przydatna. Ponieważ każdy plik o nazwie kończącej się na .py może pełnić zarówno rolę modułu, jak i programu wykonywalnego (,,głównego"), to dobrze jest, aby w kodzie zawartym w tym pliku można było rozpoznać, w jakiej roli został on uruchomiony. Jeżeli plik wykorzystywany jest w charakterze modułu, tj. poprzez instrukcję import, to:
In [4]: witaj.__name__ == 'witaj'
Out[4]: True
czyli pod nazwą __name__ kryje się napis, będący nazwą modułu. Jeżeli jednak plik został uruchomiony w charakterze programu głównego, to treścią tej nazwy będzie napis '__main__'. Jest szeroko przyjętą praktyką umieszczania poleceń, które mają być wykonywane tylko w przypadku, gdy plik zostanie uruchomiony jako program główny, wewnątrz instrukcji if:
(...)
if __name__ == '__main__':
# blok instrukcji uruchamiających program
Pozwala to na wykorzystywanie tego samego pliku w obu rolach: programu głównego, i modułu.