In [1]:
# setup
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

2. Podstawy: Instrukcje sterujące: warunki i pętle

Jak każdy język programowania Python korzysta z ograniczonego zestawu funkcji wbudowanych, instrukcji warunkowych (rozgałęzień) oraz pętli/iteracji (wielokrotnego powtarzania tego samego kodu). Wspólną cechą instrukcji warunkowych i pętli jest to że składają się one z wyrażenia (warunkowego lub iteracji) zakończonej dwukropkiem oraz bloku kodu sterowanego przez daną instrukcję. Język Python nie posiada znaczników, które pozwalają ograniczyć blok kodu ale korzysta ze wcięć do definiowania takich bloków. Z jednej strony wymusza to przejrzyste i jednoznaczne pisanie kodu z drugiej strony może być źródłem frustracji i trudnych do wykrycia błędów. Ogólna forma instrukcji sterującej wygląda następująco:

instrukcja sterujaca:
    linia kodu
    linia kodu
    linia kodu

kolejna instrukcja

Wyrażenia logiczne

Wyrażenia logiczne to wyrażenia, które zwracają True lub False. True oraz False to wartości specjalne należące do typu danych logicznego - bool. True oraz False nie są łańcuchami tekstowymi.

Wyrażeń logicznych używamy do porównania dwóch zmiennych/wartości. Istnieje kilka operatorów porównania: <, >, <=, >=, ==, !=

Operator == służy do porównania dwóch wartości. 2 == 1 oznacza porównanie liczby 2 oraz 1. Operator = (pojedyńczy znak równości) jest operatorem przypisania. x = 5 oznacza, że do zmiennej x przypiszemy wartość 5

Istnieją 3 operatory logiczne:

  • and - koniinkcja
  • or - alternatywa
  • not - zaprzeczenie

Instrukcje warunkowe

Instrukcje warunkowe pozwalają na wybranie rozwiązania, w zależnosci od tego czy wskazany warunek jest spełniony czy nie. Ogólna postać najprostrzej instrukcji warunkowej to:

if warunek: 
    wykonaj instrukcję/blok instrukcji

Jeśli warunek jest spełniony instrukcja zostanie wykonana, jeśli nie instrukcja zostanie pominięta. Najprostsza forma instrukcji warunkowej to pojedyncza instrukcja warunkowa. Poniższą instrukcję czytamy jako: Jeśli x jest większe od 0 wyświetl napis x to liczba dodatnia.

In [2]:
x = 5 
if x > 0: 
    print('x to liczba dodatnia') 
x to liczba dodatnia

Bardziej skomplikowana jest instrukcja warunkowa z dwoma możliwościami rozwiązania (ang. alternative execution), w zależnośći od tego czy warunek jest spełniony czy nie zostanie wykonana inna instrukcja:

In [3]:
if x%2 == 0 : 
    print('x to liczba parzysta')
else :
    print('x to liczba nieparzysta')
x to liczba nieparzysta

Możemy spotkać sytuacje, że istnieje więcej niż dwie możliwości rozwiązania w zależności od zaistniałej sytuacji. W takim przypadku używamy struktury zwanej łańcuchem warunków. Do budowania łancuchów warunków używamy instukcji elif, która jest skrótem od else if znanym z innych języków programowania. Nie ma ograniczeń co do ilości wyrażeń elif. Jeśli w instrukcji warunkowej występuje wyrażenia elif i else, to musi else wystąpić zawsze na końcu.

In [4]:
x=5
y=3
if x < y: 
    print('x jest mniejsze od y')
elif x > y: 
    print('x jest wieksze od y')
else: 
    print('x jest rowne y')
x jest wieksze od y

Warunki zagnieżdzone

Dużo bardziej skomplikowane struktury wykorzystują zagnieżdzanie warunków. Niestety, instrukcje zagnieżdzone stają się nieczytelne. Należy ich unikać, zwłasza w sytuacjach kiedy jest to możliwe. W części przypadków instrukcja zagnieżdzona może zostać zastąpiona operatorem logicznym and. Każdy kolejny poziom zagnieżdzania instrukcji wymusza utworzenie kolejnego bloku wcięć, co przekłada się na czytelność i zrozumiałość kodu.

Poniższy przykład ilustruje stosowanie instrukcji zagnieżdzonych. W zależności od progu prędkości wiatru (w km/h) zostanie wyświetlony inny napis informujący o typie wiatru.

In [5]:
wiatr = 19
if wiatr < 0:
    print('Niepoprawna wartosc. Podaj wartosc >=0')
elif wiatr < 30: 
    if wiatr == 0: 
        print('cisza')
    else:
        print('lekki lub umiarkowany wiatr')
elif wiatr <=62: 
    print('silny wiatr')
elif wiatr < 117: 
    print('sztorm')
else: 
    print('huragan')
lekki lub umiarkowany wiatr

Operator trójkowy

Python nie posiada klasycznego operatora trójkowego w postaci znanej z innych języków:

test ? true : false

Gdzie test oznacza test logiczny, np. a > 10, b ==7 czy inną operację zwaracjącą prawdę lub fałsz; a true operację wykonywaną gdy test zwraca prawdę natomiast false gdy zwróci fałsz. W zamian Python wprowadza nieco zmodyfikowaną formę instrukcji if-else, która ma naśladować składnię języka naturalnego (w praktyce mówimy: kup kaszę a jak nie będzie kaszy to ryż, a nie kup: jak nie będzie kaszy to ryż inaczej kaszę:

true if test else false

Jako przykład porównajmy klasyczną instrukcję if-else z instrukcją trójwarunkową, przypisującą wartość do zmiennej stan morza w zależności od siły wiatru

In [6]:
wiatr = 120
if wiatr > 120:
    stan_morza = 'Sztorm'
else:
    stan_morza = 'Nie sztorm'
print(stan_morza)

stan_morza = 'Sztorm' if wiatr > 120 else "Nie sztorm"
print(stan_morza)
Nie sztorm
Nie sztorm

Pętle

Pętle są narzędziem służącym do wielokrotnego wykonywania tego samego fragmentu kodu, najczęścej przy zmianie wartości jednej lub więcej zmiennych. Python posiada dwa rodzaje pętli, różniące się składnią:

  • pętla for stosowana w sytuacji, gdy ilość wykonań kodu jest znana przed rozpoczęciem działania pętli
  • pętla while stosowana gdy ilość wykonań nie jest znana przed zakończeniem działania pętli

W praktyce oba rodzaje pętli - tak jak w innych językach programowania są wymienne.

Pętla for

Pętle for operują na elementach listy. Oznacza to, że ilość powtórzeń pętli jest znana przed jej uruchmieniem - zostanie wykonana tyle razy ile jest elementów w liście. Lista pozwala nam na przechowywanie wielu wartości w jednym obiekie, bez konieczności tworzenia tysięcy zmiennych. Podobne zadanie spełnia pętla for. Pętla pozwala na wykonanie instrukcji dla każdego elementu z listy, bez konieczności powtarzania tej instrukcji osobno, dla każdego elementu.

Ogólna składnia pętli for to:

for <zmienna> in <lista>: 
    blok instrukcji

Powyższy zapis oznacza:

Dla (for) elementu w (in) liscie wykonaj instrukcję. Instrukcja zostanie wykonana, tyle razy, ile elementów jest w liście.

Jako przykład zastosujemy pętlę for dla wypisania poszczególnych nazw miesięcy z listy mce. W powyższym przykładzie zmiennej o nazwie miesiac zostanie przypisany kolejny element listy mce.

In [7]:
mce = ['styczen', 'luty', 'marzec', 'kwiecien', 'maj', 'czerwiec', 'lipiec', 'sierpien', 'wrzesien', 'pazdziernik', 'listopad', 'grudzien'] 
for miesiac in mce:
    print(miesiac)
styczen
luty
marzec
kwiecien
maj
czerwiec
lipiec
sierpien
wrzesien
pazdziernik
listopad
grudzien

Jak działa pętla for?

Krok 1. Do zmiennej miesiac przypisywany jest pierwszy element listy mce i dla niego wykonywany jest instrukcja (w tym wypadku print(miesiac)). Krok 2. Do zmiennej miesiac przypisywany jest drugi element listy mce i dla niego wykonywany jest instrukcja (w tym wypadku print(miesiac)). … Krok n. Do zmiennej miesiac przypisywany jest ostatni element listy mce i dla niego wykonywany jest instrukcja (w tym wypadku print(miesiac)).

Każdy taki krok obejmujący wykonanie kodu w boku instrukcji nazywany jest iteracją. W ten sposób za pomocą 2 linii kodu możemy wykonać tę samą instrukcję dla każdego elementu listy. Zaletą pętli for jest to że zakres jej działania jest ograniczony zakresem listy serującej. Oznacza to że ryzyko utworzenia pętli nieskończonej jest niewielkie.

Klasyczny sposób wykorzystania pętli for to przemieszczanie się po zakresach wartości. Zakres wartości definiujemy za pomocą funkcji wbudowanej range() (w wersji 2.x range() lub xrange()). Range można definiować poprzez wartość minimalną i makymalną +1, lub tylko przez maksymalną. Można również definiować krok zakresu. Po elementach listy można iterować również z użyciem indeksów.

In [8]:
print(range(10))
range(0, 10)
In [9]:
for i in range(3,12,2):
    print(i)
3
5
7
9
11
In [10]:
for i in range(len(mce)): 
    print(i)
    print(mce[i])
0
styczen
1
luty
2
marzec
3
kwiecien
4
maj
5
czerwiec
6
lipiec
7
sierpien
8
wrzesien
9
pazdziernik
10
listopad
11
grudzien

Pętla while

Pętla while jest wykorzystywana wtedy, gdy nie mamy listy dla której wykonywana sąinstrukcje a jedynie znamy warunek dla którego wyrażenia pętli mają być wykonywane. Oznacza to że ilość iteracji w pętli while nie jest znana. Składnia pętli while to:

while <wyrażenie warunkowe>
    <blok instrukcji>

Jak działa while?

  1. Wykonuje wyrażenie warunkowe i sprawdza czy w wyniku zwraca True czy False
  2. Jeśli warunek nie jest spełniony (False), zakończ pętla zostaje przerwana i blok instrukcji nie jest wykowany. Kod przechodzi do następnego wyrażenia (w powyższym przykładzie wyświetl 'Koniec').
  3. Jeśli warunek jest spełniony (True) wykonaj instrukcję wewnątrz bloku instrukcji i ponownie sprawdź wyrażenie warunkowe (przejdź do punktu 1).

Blok instrukcji wewnątrz pętli while powinien zmieniać wartość jednej lub kilku zmiennych zawartych w wyrażeniu warunkowym, tak aby w końcu warunek został spełniony i pętla się zakończyła. Zmienną, która przy każdej iteracji zmienia swoją wartość i w ten sposób kontroluje, kiedy pętla się zakończy nazywamy zmienną iteracyjną. W przypadku gdy w pętli nie będzie zmiennej iteracyjnej pętla będzie się wykonywać w nieskończoność (infinite loop).

In [11]:
n = 5 
while n >= 0:
    print(n)
    n = n -1
print('Koniec')
5
4
3
2
1
0
Koniec

Łączenie pętli i wyrażeń warunkowych

Blokiem instrukcji w pętli for lub while może być także instrukcja warunkowa. Dzięki osadzeniu instrukcji if, działanie obu rodzaju pętli może zostać zmodyfikowane przy pomocy specjalnych instrukcji pass, break i continue

  • instrukcja pass służy do wykonania iteracji (np warunku), jeżeli nie chcemy jednak wykonywać poleceń
  • instrukcja continue pomija wykonanie wszyskich poleceń danej iteracji i rozpoczęcie kolejnej
  • instrukcja break powoduje natychmiastowe przerwanie pętli
In [12]:
for i in range(7):
    if(i == 3): # zastosowanie pass jest w praktyce ograniczone
        pass
    print(i)
0
1
2
3
4
5
6
In [13]:
for i in range(7):
    if(i == 3): # pomijamy 3
        continue
    print(i)
0
1
2
4
5
6
In [14]:
for i in range(7):
    if(i == 3): # kończymy przed 3
        break
    print(i)
0
1
2

Pętle zagnieżdzone

Podobnie jak w przypadku list pętle mogą być zagnieżdżone. Pętle zagnieżdżone mogą iterować po kolejnych elementach listy lub po zakresach. Zakres zagnieżdzony jest resetowany za każdym razem, gdy wykonywana jest iteracja nadrzędna.

In [15]:
pop_dens = [['Azja', 246], ['Europa', 188], ['Afryka', 87], ['AmerykaS', 57], ['AmerykaN', 57], ['Australia', 8.3] , ['Antarktyda', 0.00078]]

for item in pop_dens:
    print(item)
['Azja', 246]
['Europa', 188]
['Afryka', 87]
['AmerykaS', 57]
['AmerykaN', 57]
['Australia', 8.3]
['Antarktyda', 0.00078]
In [16]:
for lista_wewnetrzna in pop_dens:
    for item in lista_wewnetrzna:     
        print(item)
Azja
246
Europa
188
Afryka
87
AmerykaS
57
AmerykaN
57
Australia
8.3
Antarktyda
0.00078

Note: sprawdzanie czy zmienna jest jednym z wielu typów:

W sytuacji, gdy chcemy sprawdzić czy obiekt pasuje do więcej niż jednego typu danych, zamiast stosować warunek:

python 
if type(x) == int or type(x) == float:
    pass

Można zastąpić poznanym już operatorem in:

In [17]:
x = 6
type(x) in (str,float)
Out[17]:
False