Wstęp do pythona
Kilka słów o języku programowania python. Skupimy się na używaniu tego języka pozostawiając szczegóły techniczne na boku.
Spis treści
Jak w ogóle działa język programowania i co to jest?
Komputery są przydatne o tyle, o ile potrafią wykonać to, czego od nich chcemy.
Jednym ze sposobów przekazywania innym czego od nich oczekujemy są instrukcje. Możemy na przykład poprosić rodzeństwo, żeby nie dotykało tej kupki części i... Przynajmniej mieć nadzieję, że instrukcje zostaną wykonane.
Jednak pomijając kłopoty komunikacyjne zastanówmy się chwilę co właściwie zrobiliśmy. Po pierwsze użyliśmy znanego sobie i rodzeństwu języka (polskiego) z jego wszystkimi zasadami wymowy/gramatyki, i przy pomocy dość skomplikowanej aparatury (nasze aparat mowy --> powietrze --> uszy rodzeństwa) przekazaliśmy pewną myśl określającą jakiego zachowania oczekujemy. W kontaktach z ludźmi robimy to odruchowo i zupełnie nie zastanawiamy się ile ciekawych procesów musi się udać, żeby to wszystko zadziałało.
Na tym samym polega programowanie komputerów, ale ponieważ do niedawna komputery kompletnie nie rozumiały zwykłego języka mówionego informatycy nie używają języków naturalnych. Zamiast tego opracowali o wiele prostsze i bardziej precyzyjne języki programowania. Ponadto zrezygnowali z rozmów z komputerami i przyjęli zasadę, że treść programu trzeba dostarczyć "na piśmie" jako plik tekstowy (lub tekst wprowadzony z klawiatury).
Niestety oznacza to, że to my musimy nauczyć się zapisywać swoje intencje w takim języku, który komputer "rozumie". W nagrodę będziemy mogli wykorzystywać go do różnych, mniej lub bardziej przydatnych zajęć, a on będzie będzie robił co każemy dopóki starczy prądu. Jednym programistom podoba się używanie komputerów do wyświetlania wirtualnych światów, w których inni ludzie lubią przebywać. Innym podoba się tworzenie instrukcji, dzięki którym komputer potrafi samodzielnie kierować samochodem. Kody pisane przez niektórych sterują sondami w przestrzeni kosmicznej, które muszą samodzielnie reagować na zmieniającą się sytuację (są zbyt daleko żeby człowiek mógł reagować na bieżąco!), a jak widać na filmach poniżej są też tacy, którzy tworzą zestawy instrukcji do tańca na śniegu albo sprytnych piesków. Tak czy inaczej, jak widać programiści potrafią wykrzesać z komputerów sporo i nauczenie się choćby jednego języka programowania może być początkiem ciekawej przygody (dobrym przykładem może być Polak, którego drętwe zdjęcie z obozu informatycznego stało się kiedyś przebojem demotywatorów, a on teraz programuje samodzielnie lądujące rakiety SpaceX).
Okazuje się więc, że pomimo prostoty języków programowania, potrafimy z ich pomocą wyrażać naprawdę skomplikowane instrukcje oraz zupełnie nieźle się przy tym bawić!
Warto zwrócić uwagę na fakt, że maszyny ciągle jeszcze są bezmyślne i z chęcią zrealizują dowolne instrukcje o ile tylko zapiszemy je w zrozumiały dla nich sposób. Niestety ta zaleta komputerów jest jednocześnie ich najgorszą wadą. Kiedy instrukcje są bez sensu, maszyny wykonają działanie bez sensu bez żadnego sprzeciwu! Niestety z tego powodu programowanie przypomina opiekę nad bardzo szybkim, ale jednak ciągle "osiołkiem", który się sam nie domyśli, że coś robi źle.
Praktyczna zasada: Jeżeli myślisz, że to "komputer robi coś głupiego", to najwyższa pora przemyśleć instrukcje, które otrzymał; już dłużej nie da się zwlekać.
Jak zacząć programować?
Wystarczy włączyć terminal i wpisać polecenie python.
ktos@maszyna:~$ python Python 2.7.11+ (default, Apr 17 2016, 14:00:29) [GCC 5.3.1 20160413] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>>
W odpowiedzi zostaje uruchomiony program, który czeka na nasze instrukcje i będzie je wykonywał w miarę wpisywania. Stan oczekiwania na instrukcje sygnalizowany jest wyświetleniem >>> na początku linii. Na samym początku python wyświetla też kilka dodatkowych technicznych informacji na temat języka, oraz zachętę do skorzystania z kilku instrukcji w celu poznania dalszych szczegółów. Możemy te linijki zignorować.
Kiedy już skończymy wykonywanie różnych instrukcji pythona możemy zakończyć jego działanie i wrócić do linii poleceń terminala używając kombinacji klawiszy Ctrl-D. Możesz to sprawdzić od razu, ale nie zapomnij ponownie uruchomić pythona przed przejściem do następnych przykładów.
Kilka prostych instrukcji i konstrukcji języka python na rozgrzewkę
Dla wygody poniżej posługujemy się kolorowaniem składni. W terminalu nie będzie ono widoczne, ale dzięki niemu poniższe przykłady czyta się łatwiej.
print (ang. drukuj), czyli wyświetlanie napisów
Spróbujmy wykonać jedną z prostszych instrukcji, która wypisuje jakiś tekst. Ona może być przydatna na przykład do wyświetlenia wyników, albo pokazania stopnia zaawansowania obliczeń jeśli program działa długo, lub ogólnie wszędzie tam, gdzie chcemy żeby program "zagadał" do użytkownika.
>>> print("Nie będę śpiewał kołysanek na lekcji")
Nie będę śpiewał kołysanek na lekcji
>>>
Jak widać programowanie w pythonie jest zupełnie proste. Napisaliśmy nazwę funkcji (print) po czym w nawiasie podaliśmy parametr (tutaj tekst, który należy wydrukować) i tyle. Ponieważ interpreter pythona pracuje w trybie interaktywnym i wykonuje instrukcje zaraz po ich podaniu, po naciśnięciu ENTER zobaczymy efekt działania, czyli nasz tekst.
Zwróć uwagę, że tekst otoczony jest znakami cudzysłowu. Gdybyśmy go napisali bez nich, na przykład zamiast print( "print")
byłoby print( print )
, mogłoby być trudno w niektórych sytuacjach zrozumieć, które słowa należy traktować jak zwykły kawałek tekstu do wyświetlenia, a które należy interpretować jako instrukcje programu. Kiedy jednak napiszemy print( "print" )
będzie oczywiste, że pierwsze print to instrukcja drukowania, a drugie print to tylko jakiś tekst, który ma być wypisany, i wobec tego python bez problemu wyświetli napis print
.
Jak widać powyżej tekst został wyświetlony w pierwszej pustej linii na ekranie, a zaraz pod nim ponownie znak oczekiwania na kolejną instrukcję. Wszystko razem wygląda trochę ciasno. Żeby temu zaradzić dodajmy zarówno przed tekstem jak i po nim znak przejścia do nowej linii. Przejście do nowej linii zostawi pustą linijkę dzięki czemu wyświetlony komunikat będzie się lepiej wyróżniał.
>>> print("\nNie będę śpiewał kołysanek na lekcji\n")
Nie będę śpiewał kołysanek na lekcji
>>>
A co jeśli chcielibyśmy wyświetlony tekst powtórzyć? Python pozwala użyć mnożenia w tym celu.
>>> print("\nNie będę śpiewał kołysanek na lekcji"*5)
Nie będę śpiewał kołysanek na lekcji
Nie będę śpiewał kołysanek na lekcji
Nie będę śpiewał kołysanek na lekcji
Nie będę śpiewał kołysanek na lekcji
Nie będę śpiewał kołysanek na lekcji
>>>
Wyświetlanie napisu wielokrotnie ma raczej mały sens ale, choć dla człowieka takie zadanie byłoby karą, komputer wykonuje kod bez problemu. Jeśli pomyłkowo pomnożymy napis milion razy, funkcja print cierpliwie wyświetli milion napisów...............
Na wszelki wypadek dodajmy przy okazji, że zbyt długo pracujący program można przerwać kombinacją klawiszy Ctrl-C.
Czasem jednak powielenie tekstu może być przydatne. Na przykład przepis na wyświetlenie choinki mógłby wyglądać tak (zwróć uwagę, że jeśli w jednej linii podajemy wiele instrukcji -- tutaj print -- to rozdzielamy je średnikiem ;):
>>> print(" "*10 + "^"*1); print(" "*9 + "^"*3); print(" "*8 + "^"*5);print(" "*7 + "^"*7);print(" "*6 + "^"*9);
^
^^^
^^^^^
^^^^^^^
^^^^^^^^^
>>>
Dzięki temu, że możemy łatwo powielić tekst poprzez mnożenie, stworzenie choinki składającej się z coraz krótszych kawałków spacji (10, 9, 8, 7, 6) oraz coraz dłuższych pięter choinki (znaki ^ powtórzone 1, 3, 5, 7 i 9 razy) było proste w zapisie. Jeśli nie wierzysz, spróbuj za pierwszym razem uzyskać ładną symetryczną choinkę licząc znaki poszczególnych pięter samemu i wstawiając odpowiednio długie ciągi znaków w kolejnych instrukcjach print.
Drukując napisy możemy jeszcze skorzystać z jednej bardzo przydatnej funkcji pythona. Bardzo często kiedy wyświetlamy jakiś komunikat na ekranie, chcielibyśmy w standardowym dłuższym tekście odpowiednio dopasować tylko jego krótki fragment. Na przykład gdybyśmy chcieli przywitać użytkownika, standardowy tekst mógłby brzmieć Witaj ..., miło Cię zobaczyć znowu! gdzie w miejsce ... wstawiałoby się tylko imię użytkownika.
Do tego celu można się posłużyć następującą konstrukcją:
>>>print("\nNie będę śpiewał %s kołysanek na lekcji\n" % "dziwnych")
Nie będę śpiewał dziwnych kołysanek na lekcji
>>>
Co zrobiliśmy? W tym miejscu tekstu, gdzie chcielibyśmy wstawić inny, umieściliśmy znacznik %s i dalej, już poza tekstem, po znaku % podaliśmy wartość, którą należy wstawić w zaznaczone miejsce. Posłużmy się jeszcze innym przykładem, w którym wstawiamy dwa różne teksty do innego.
>>>print("\nNie będę śpiewał %s kołysanek na lekcji %s\n" % ("dziwnych", "matematyki"))
Nie będę śpiewał dziwnych kołysanek na lekcji matematyki
>>>
A co jeśli chcielibyśmy wstawić nie tekst, ale liczbę? Wówczas musimy zastosować inny znacznik, czyli %d.
>>> print("\nNie będę śpiewał %s kołysanek na %d lekcji %s\n" % ("dziwnych", 2, "matematyki"))
Nie będę śpiewał dziwnych kołysanek na 2 lekcji matematyki
>>>
W tej chwili powyższa konstrukcja może się wydawać zbyteczna -- widać, że prościej byłoby zapisać całe zdanie od razu tak jak miało brzmieć. Ale jej przydatność wyjaśni się już w następnym punkcie.
zmienna, czyli jak pamiętać to co program przetwarza
Byłoby bardzo wygodnie, gdyby dało się napisać instrukcję powodującą zapisanie w pamięci komputera jakiegoś wyniku, który za chwilę wykorzystamy w dalszym ciągu programu. Taki podręczny "schowek" na dane to zmienna. W pythonie jej stworzenie jest zupełnie banalne, na przykład:
>>> jakas_liczba = 5
>>>
Wygląda tak, jakby nic się nie stało, ale wystarczy wpisać nazwę nowo zdefiniowanej zmiennej, a python wyświetli jej wartość, co oznacza, że ją zapamiętał!
>>> jakas_liczba
5
>>>
Co więcej, od teraz wszędzie, gdzie powołamy się na nazwę zmiennej otrzymamy jej aktualną wartość.
>>> jakas_liczba + 7
12
>>> jakas_liczba - 3
2
>>> print(":" + ")" * jakas_liczba)
:)))))
>>>
Ta prosta konstrukcja języka okazuje się bardzo użyteczna. Za chwilę poznamy różne inne zastosowania, ale już teraz możemy powiedzieć, że zmienna będzie się pojawiała co chwilę i bez niej wielu przydatnych rzeczy nie dałoby się wykonać.
Ponieważ wiemy już jak działa zmienna możemy wrócić do przykładu drukowania napisów, w którym wstawialiśmy do drukowanego tekstu inne treści. Załóżmy, że mierzymy co 1/10 sekundy prędkość naszego pojazdu i chcemy ją wyświetlić zarówno w metrach na sekundę jak i w kilometrach na godzinę. Jeśli wynik pomiaru zapiszemy sobie w zmiennej predkosc wówczas następująca instrukcja pozwoli nam drukować aktualnie zmierzoną wartość w sposób zrozumiały i wygodny dla człowieka (dla przykładu zmieniamy wartość prędkości dwa razy, żeby zasymulować różne pomiary):
>>> predkosc = 3.21
>>> print("\nAktualna prędkość wynosi %f [m/s] (= %f [km/h])\n" % (predkosc, predkosc * 3.6))
Aktualna prędkość wynosi 3.210000 [m/s] (= 11.556000 [km/h])
>>> predkosc = 5.111
>>> print("\nAktualna prędkość wynosi %f [m/s] (= %f [km/h])\n" % (predkosc, predkosc * 3.6))
Aktualna prędkość wynosi 5.111000 [m/s] (= 18.399600 [km/h])
>>>
Zwróć uwagę, że do wyświetlania liczb z przecinkiem używamy znacznika %f.
Nieco dłuższe programy
Powyżej widzieliśmy instrukcje, które mieszczą się w jednej linijce. Moglibyśmy kontynuować pisanie programów w ten sposób, ale za chwilę stałoby się to mało wygodne, a już na pewno mało czytelne. Musimy więc wyjaśnić jak pracować z dłuższymi programami. Na szczęście jest to całkiem proste.
Całe zadanie sprowadza się do zapisania tekstu programu w pliku i potem przekazania go interpreterowi pythona do wykonania.
Dla przykładu weźmy ostatni przykład powyżej. Składa się z dwóch instrukcji: ustawienia wartości zmiennej predkosc
i wyświetlenia jej wartości w metrach na sekundę oraz kilometrach na godzinę. Otwórzmy więc dowolny edytor tekstu (na przykład gedit) i w nowym pliku wstawmy te dwie instrukcje:
# coding: utf-8
predkosc = 5.111
print("\nAkualna prędkość wynosi %f [m/s] (= %f [km/h])\n" % (predkosc, predkosc * 3.6))
Teraz zapiszmy plik z dowolną nazwą na dysku. Warto dać mu rozszerzenie .py (jak python), które jest standardowym oznaczeniem dla programów w pythonie. Jeśli tak zrobimy gedit powinien to zauważyć i zacząć kolorować składnię dzięki czemu kod będzie czytelniejszy.
Jeśli użyliśmy nazwy pliku pierwszy.py
możemy wykonać program wywołując polecenie:
ktos@maszyna:~ $ python pierwszy.py
Akualna prędkość wynosi 5.111000 [m/s] (= 18.399600 [km/h])
ktos@maszyna:~ $
Jak widać program działa tak samo jak w powyżej.
Natomiast teraz możemy umieścić w pliku nie jedną, ale wiele instrukcji i napisać dzięki temu dłuższy kod robiący ciekawsze rzeczy!
Dodatkowa pierwsza linijka # coding: utf-8
jest potrzebna dlatego, że nasz w tekście programu używamy polskich znaków diakrytycznych (słowo prędkość ma trzy). Bez ustawienia kodowania obejmującego polskie znaki (czyli UTF-8) python nie spodziewa się innych liter niż angielskie i zamiast wykonać program wyświetli jedynie rozpaczliwy komunikat, że nie rozumie znaków spoza standardu ASCII (jest to stary standard kodowania znaków jeszcze z poprzedniego wieku):
File "/home/ktos/pierwszy.py", line 2
SyntaxError: Non-ASCII character '\xc4' in file /home/ktos/pierwszy.py on line 2,
but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
Warto zauważyć, że nowe wersje pythona, tj. 3+, domyślnie używają bardziej uniwersalnego UTF-8, więc jeśli używasz pythona 3 lub nowszego linijka # coding: utf-8
nie jest potrzebna do pracy z polskimi znakami.
Przy okazji zauważmy, że to co znajduje się w linijce po znaku # traktowane jest przez interpreter jako komentarz, a więc to co jest tam napisane nie będzie wykonywane jako program. Linie komentarza przydają się, żeby choćby samemu sobie napisać wskazówkę o co chodziło w kodzie, który jest w pobliżu. W bardzo długich programach można się szybko pogubić i rozsądnie napisany komentarz bardzo ułatwia życie. Na przykład:
# coding: utf-8
predkosc = 5.111
# Przelicznik 3.6 bierze się stąd, że 1 [km/h] = (1000 [m] / 3600 [s] = 1000/3600 [m/s] ) = 1/3.6 [m/s],
# skąd wynika odwrotna zależność że 1 [m/s] = 3.6 [km/h]
print("\nAkualna prędkość wynosi %f [m/s] (= %f [km/h])\n" % (predkosc, predkosc * 3.6))
Kilka wielolinijkowych konstrukcji języka python
Skoro potrafimy już używać programów składających się z wielu linijek zajmijmy się dłuższymi konstrukcjami języka.
instrukcja warunkowa, czy co robić jeśli tak, a co jeśli nie
Wracając do przykładu z rozmów między ludźmi dość często przekazując instrukcje używamy poleceń warunkowych nawet nie bardzo uświadamiając sobie ten fakt. Często uzależniamy działanie od jakiegoś wstępnego warunku mówiąc na przykład: Jeśli X zadzwoni o osiemnastej to będę musiał ..., a jak nie zadzwoni to możemy ....
Dokładnie tak samo możemy chcieć zaprogramować komputer. Na przykład jeśli na przeciwko robota stoi przeszkoda (sprawdzamy co podaje jakiś czujnik) to należy wykonać jej omijanie, a jeśli przeszkody nie ma, można kontynuować jazdę do przodu.
Do sterowania programem w ten sposób służy właśnie instrukcja warunkowa, której schemat przedstawiony jest poniżej.
if warunek:
# instrukcje do wykonania
# jeśli warunek jest spełniony
...
else:
# a tu instrukcje w przeciwnym przypadku
# czyli jeśli warunek nie jest spełniony
...
# ciąg dalszy programu
...
Zastosujmy instrukcję warunkową do modyfikacji wyświetlania komunikatu powyżej:
# coding: utf-8
predkosc = 5.111
if predkosc < 50:
# wyświetlamy tak samo jeśli zmierzona prędkość wydaje się rozsądna
print("\nAkualna prędkość wynosi %f [m/s] (= %f [km/h])\n" % (predkosc, predkosc * 3.6))
else:
# Robot przypadkiem wjechał na tory Pendolino?
print("\nCzujnik zwariował!!! Ten robot nie może jechać z prędkością %f [m/s] (= %f [km/h])\n" % (predkosc, predkosc * 3.6))
Spróbuj zapisać ten program z różnymi wartościami prędkości i wykonać.
W przypadku wielolinijkowych konstrukcji pythona trzeba zwrócić uwagę na wcięcia linijek. Nie przypadkiem te instrukcje, które mają się wykonać dla spełnionego, i osobno dla niespełnionego, warunku są przesunięte o 4 spacje w prawo. Tylko dzięki temu przesunięciu interpreter pythona wie, które instrukcje wykonywać w zależności od spełnionego warunku. Popatrzmy na taki przykład:
# coding: utf-8
poziom_energii = 2.0
if poziom_energii < 1.0: # Z powodu wcięcia tekstu programu dwie następne instrukcje wykonają się zależnie od warunku.
print("UWAGA: Energia się kończy!")
print("Najbliższa stołówka za rogiem!")
print("Aktualnie masz %f kcal energii." % poziom_energii) # Ta instrukcja nie zależy od warunku i wykona się zawsze.
Jak zwykle warto uruchomić ten program ze zmienną poziom_energii
mniejszą niż 1.0
żeby zobaczyć jego działanie w dwóch różnych przypadkach.
pętla, czyli to co komputer potrafi robić bez znudzenia
Bardzo często chcemy jakieś instrukcje powtórzyć określoną ilość razy. Na przykład chcielibyśmy po kolei zapalić diody podłączone do wyjść GPIO o numerach od 5 do 15. Moglibyśmy zapisać 10 następujących poleceń:
# pominięte instrukcje wczytujące moduł obsługi wyjść GPIO oraz inicjujące płytkę
#
gpio.output(5, 1)
gpio.output(6, 1)
gpio.output(7, 1)
gpio.output(8, 1)
gpio.output(9, 1)
gpio.output(10, 1)
gpio.output(11, 1)
gpio.output(12, 1)
gpio.output(13, 1)
gpio.output(14, 1)
gpio.output(15, 1)
Jednym słowem -- horror. Gdybyśmy chcieli zapalić na przykład 1024*768 diod w przeciętnym ekranie komputera przy takim sposobie kodowania musielibyśmy napisać blisko milion instrukcji!!!
Na szczęście można to zrobić prościej. Wystarczy zastosować pętlę. Powyższy program zapisany z jej użyciem jest o wiele krótszy:
# pominięte instrukcje wczytujące moduł obsługi wyjść gpio oraz inicjalizujące płytkę
# ....
for numer in range(5, 16):
gpio.output(numer, 1)
Co tu się dzieje dokładnie? Przede wszystkim funkcja range (ang. zakres) zwraca listę numerów z podanego przedziału z pominięciem ostatniego elementu. Sprawdźmy na przykład co zwróci użyte powyżej range(5,16)
:
>>> range(5,16)
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
>>>
Jak widać lista zaczyna się od 5, ale na końcu nie ma liczby 16.
Po angielsku for oznacza dla, in to po polsku w. Jeśli przepiszemy tekst programu po polsku, jego działanie stanie się praktycznie oczywiste
dla numer w zakresie(5, 16): gpio.output(numer, 1)
czyli wykonaj instrukcję gpio.output(numer, 1)
podstawiając do zmiennej numer kolejne liczby z podanego zakresu. Proste prawda?
Jeśli chciałoby się sprawdzić, że rzeczywiście zmienna numer zmienia się w podanym zakresie wystarczy ją wydrukować poznaną wcześniej instrukcją print.
>>> for numer in range(5,16): print(numer);
...
5
6
7
8
9
10
11
12
13
14
15
>>>
Załóżmy, że chcielibyśmy mrugnąć jedną diodą 20 razy. Nic prostszego! Wystarczy pętla o 20 krokach w środku której wykonamy jedno pełne mrugnięcie (a więc zapalenie, odczekanie chwilę, zgaszenie i znów odczekanie):
# pominięte instrukcje wczytujące moduł obsługi wyjść gpio, moduł obsługi czasu time, oraz inicjalizujące płytkę
# ...
for powtorka in range(1, 21): # Pamiętaj, że range(1, 21) zwróci [1,2,...,20], bez 21.
gpio.output(numer, 1)
time.sleep(0.5)
gpio.output(numer, 0)
time.sleep(0.5)
Wielokrotnie taka konstrukcja się przyda. Na przykład, kiedy będziemy chcieli wykonać dokładnie 35 kroków silnika krokowego zamontownego po lewej stronie robota zapewne użyjemy pętli podobnej do takiej:
# pominięte instrukcje wczytujące moduł obsługi silnika
# ...
for powtorka in range(1, 36):
krok(SILNIK_LEWY, DO_PRZODU)