Python - wprowadzenie

06 - Instrukcje wyboru

Jeżeli… - czyli instrukcje wyboru (if, elif, else)

Kod, który pisaliśmy dotychczas wykonywał się od początku do końca zawsze w ten sam sposób. Bardziej złożone programy, zwykle potrafią w różny sposób sterować przebiegiem działania w zależności, na przykład, od tego jakie dane wprowadzimy. Instrukcją, która to umożliwia jest if, której często towarzyszą elif i else. Zacznijmy od prostego przykładu. Uwaga! Przepisując kod pilnuj odpowiedniego przesunięcia (czyli wcięcia) kodu, tak jak to napisano poniżej.

# Przypisanie wartości boolowskiej do zmiennej test
test = True
# Jeżeli zmienna test ma wartość true to napisz "prawda"
if test:
    print("Prawda")
Prawda

Jak widać, program wydrukował Prawda.

Teraz nieco zmodyfikujmy kod, przypisując zmiennej test wartość False:

# Przypisanie wartości boolowskiej do zmiennej test
test = False
# Jeżeli zmienna test ma wartość true to napisz "prawda"
if test:
    print("Prawda")

Tym razem nie ma żadnego wyniku.

Po instrukcji if znajduje się wyrażenie, które powinno zwracać wartość True lub False. Następnie występuje znak :. Kolejna linia jest ,,wcięta'' w stosunku do poprzedniej. Zaleca się, żeby takie wcięcie miało cztery spacje. Edytory, które są dostosowane do programowania w tym języku, powinny po naciśnięciu Enter-a po dwukropku automatycznie wprowadzić w kolejnej linii (i następnych) odpowiedni odstęp. Linie kodu które są przesunięte, stanowią blok kodu, który będzie wykonywany jeżeli wyrażenie po if zwróci wartość True.

Jeśli dalej wpiszemy kolejne linie kodu, ale już bez wcięcia, będą wykonywane tak, czy inaczej:

# Przypisanie wartości boolowskiej do zmiennej test
test = False
# Jeżeli zmienna test ma wartość true to napisz "prawda"
if test:
    print("Prawda")
print(f"Wartość zmiennej `test` = {test}.\nKoniec programu.")
Wartość zmiennej `test` = False.
Koniec programu.

Warto w tym miejscu podkreślić, że w przeciwieństwie do wielu innych języków, np. Javy, blok kodu wykonywany po wyrażeniach typu if, nie jest specjalnie ograniczony szczególnymi znakami ({ i }) ale jego granice ograniczają właśnie wcięcia. Taki blok może mieć wiele linii, każda powinna być tak samo przesunięta w odniesieniu do początku linii. W wielu językach takie wcięcia mają znaczenie wyłącznie dla czytelności kodu, w Pythonie są obowiązkowe.

Powyższy kod sprawdzał wartość zmiennej test i wykonywał kod, jeżeli zwracała ona wartość True drukowany był tekst ,,Prawda'', jeśli zwracana była wartość False nic się nie działo. Często jednak chcielibyśmy, żeby w obu przypadkach był wykonywany jakiś kod. Można to zrobić w ten sposób:

# Przypisanie wartości boolowskiej do zmiennej test
test = False
# Jeżeli zmienna test ma wartość true to napisz "prawda"
if test:
    print("Prawda")
# W innym przypadku napisz "Fałsz"
else:
    print("Fałsz")
print(f"Wartość zmiennej `test` = {test}.\nKoniec programu.")
Fałsz
Wartość zmiennej `test` = False.
Koniec programu.

Teraz, jeśli zmienna test nie zwraca wartości True wypisuje ,,Fałsz''. Ten program ma jednak tę wadę, że tak naprawdę nie sprawdza, czy zmienna zwraca wartość False, w takim prostym przypadku to wystarcza, ale nie zawsze.

Napiszmy teraz program, który sprawdzi, czy do zmiennej jest przypisane True, False, czy może jakaś inna wartość. Będziemy mieli w tym przypadku trzy możliwości:

  1. Zmiennej jest przypisana wartość True.
  2. Zmiennej jest przypisana wartość False.
  3. Zmiennej jest przypisana jakaś inna wartość.

Przyda się tu kolejne wyrażenie: elif, które można rozumieć jako skrót od ,,else if''. Występuje ono po if i podobnie jak po if umieszczamy po nim wyrażenie, które powinno zwracać True, lub False. Wykonuje się ono wtedy, gdy if zwraca False. Modyfikację naszego programu zacznijmy od przypisania innej wartości zmiennej test:

# Przypisanie wartości do zmiennej test
test = 4
# Jeżeli zmienna test ma wartość true to napisz "prawda"
if test:
    print("Prawda")
# W innym przypadku napisz "Fałsz"
else:
    print("Fałsz")
print(f"Wartość zmiennej `test` = {test}.\nKoniec programu.")
Prawda
Wartość zmiennej `test` = 4.
Koniec programu.

Wynik może być początkowo zaskakujący. Przypomnij sobie jednak lekcję o zmiennych. Liczby inne niż 0 w przypadku konwersji na wartość boolean (a taka tu zachodzi) konwertowane są na True. Zmodyfikujmy nieco nasz program:

# Przypisanie wartości do zmiennej test
test = 4
# Jeżeli zmienna test ma wartość true to napisz "prawda"
if test == True:
    print("Prawda")
# W innym przypadku napisz "Fałsz"
else:
    print("Fałsz")
print(f"Wartość zmiennej `test` = {test}.\nKoniec programu.")
Fałsz
Wartość zmiennej `test` = 4.
Koniec programu.

Tym razem zastosowaliśmy operator ==, który służy do testowania równości, zwróć uwagę, że składa się on z dwu znaków =. Nie należy go mylić, co jest częstym błędem początkującego programisty z operatorem przypisania =. Jeśli w programie, który będziesz pisać występują tylko możliwe wartości True lub False zamiast używania operatora == zalecane jest raczej stosowanie metody testowania stosowanej poprzednio.

Teraz uzupełnimy nasz program używając wyrażenia elif:

# Przypisanie wartości do zmiennej test
test = 4
# Jeżeli zmienna test ma wartość true to napisz "prawda"
if test == True:
    print("Prawda")
# W innym przypadku sprawdź czy "False"
elif not test:
    print("Fałsz")
# Pozostałe przypadki
else:
    print("Inna wartość")
print(f"Wartość zmiennej `test` = {test}.\nKoniec programu.")
Inna wartość
Wartość zmiennej `test` = 4.
Koniec programu.

Zauważ, że do sprawdzenia czy zmienna ma wartość false użyliśmy operatora not. Jest to operator logiczny, który odwraca znaczenie wyrażenia znajdującego się po nim, czyli np. odwraca True na False.

Sprawdź jak zachowa się powyższy skrypt, jeśli zmiennej przypiszemy wartości 0, 1, "A". Wyjaśnij wyniki.

Operatory porównań

Operator == jest jednym z operatorów relacji (porównań). Pozwala na porównanie dwu wartości i uzyskanie wartości True lub False w zależności od tego czy są one równe, czy nie. Na przykład:

# Porównanie dwu liczb.

# Pobranie liczb od użytkownika
liczba1 = int(input('Podaj pierwszą liczbę całkowitą: '))
liczba2 = int(input('Podaj drugą liczbę całkowitą: '))

# Sprawdzenie, czy liczby są równe
if liczba1 == liczba2:
    print('Liczby są równe')
else:
    print('Liczby różnią się')

Podaj pierwszą liczbę całkowitą:  2
Podaj drugą liczbę całkowitą:  3

Liczby różnią się

Jeśli chcielibyśmy sprawdzić, czy liczby nie są równe, możemy użyć operatora !=:

# Porównanie dwu liczb.

# Pobranie liczb od użytkownika
liczba1 = int(input('Podaj pierwszą liczbę całkowitą: '))
liczba2 = int(input('Podaj drugą liczbę całkowitą: '))

# Sprawdzenie, czy liczby są równe
if liczba1 != liczba2:
    print("Liczby różnią się")
else:
    print("Liczby są równe")
    
Podaj pierwszą liczbę całkowitą:  2
Podaj drugą liczbę całkowitą:  3

Liczby różnią się

Kolejne dwa operatory, znane nam z lekcji matematyki to > (większy) i < (mniejszy). Zmodyfikujmy nasz program:

# Porównanie dwu liczb.

# Pobranie liczb od użytkownika
liczba1 = int(input('Podaj pierwszą liczbę całkowitą: '))
liczba2 = int(input('Podaj drugą liczbę całkowitą: '))

# Sprawdzenie, czy liczba1 jest większa niż liczba2
if liczba1 > liczba2:
    print("Pierwsza liczba jest większa niż druga liczba")
# Sprawdzenie, czy liczba1 jest mniejsza niż liczba2
elif liczba1 < liczba2:
    print("Pierwsza liczba jest mniejsza niż druga liczba")
# Jeśli liczba1 nie jest ani większa ani mniejsza niż liczba2
# to znaczy, że są równe
else:
    print("Liczby są równe")
Podaj pierwszą liczbę całkowitą:  2
Podaj drugą liczbę całkowitą:  7

Pierwsza liczba jest mniejsza niż druga liczba

Do kompletu brakuje nam jeszcze operatorów: >= (większy lub równy) oraz <= (mniejszy lub równy). Ważne, aby nie pomylić kolejności znaków w tych wyrażeniach.

Podsumujmy poznane operatory relacji (porównań):

Operator znaczenie przykład wynik
== równość 2 == 4 False
!= nierówność 2 != 4 True
> większe 2 > 4 False
< mniejsze 2 < 4 True
>= większe lub równe 2 >= 4 False
<= mniejsze lub równe 2 <= 4 True

Porównywanie ciągów znaków

Powyżej porównywaliśmy liczby, ale można także porównać ciągi znaków:

# Porównanie ciągów znaków

# Pobranie odpowiedzi od użytkownika
odpowiedz = input('Podaj hasło: ')
# Porównanie podanego hasła z właściwym
if odpowiedz == 'Python':
    print('Witaj w skarbcu!')
else:
    print('Niestety, błedne hasło!')

Podaj hasło:  Python

Witaj w skarbcu!

Teraz bardziej złożony przykład:

# Znaczenie skrótów zasad azotowych

# Pobranie litery od użytkownika:
litera = input('Podaj literę oznaczającą zasadę azotową: ')
if litera == 'A':
    print(f'Litera {litera} to adenina')
elif litera == 'C':
    print(f'Litera {litera} to cytozyna')
elif litera == 'G':
    print(f'Litera {litera} to guanina')
elif litera == 'T':
    print(f'Litera {litera} to tymina')
elif litera == 'U':
    print(f'Litera {litera} to uracyl')
else:
    print(f'Podałeś {litera} - błędna litera')

Podaj literę oznaczającą zasadę azotową:  G

Litera G to guanina

Pisząc tego typu programy, pamiętaj aby przetestować możliwie szerokie spektrum możliwych danych. Tu na przykład należałoby sprawdzić, czy program podaje poprawne odpowiedzi dla każdej z liter odpowiadających zasadom a także ciągów znaków spoza tej piątki.

Powyższy program ma tę wadę, że jeśli użytkownik poda małą, zamiast wielkiej litery to uzyska komunikat o błędnej literze, np:

Podaj literę oznaczającą zasadę azotową:  a
Podałeś a - błędna litera

Ćwiczenie: Zastanów się jak uniknąć tej niedogodności.

Można to zrobić w ten sposób:

# Znaczenie skrótów zasad azotowych

# Pobranie litery od użytkownika:
litera = input('Podaj literę oznaczającą zasadę azotową: ')
# Sprawdzenie znaczenia poszczególnych liter
if litera.upper() == 'A':
    print(f'Litera {litera} to adenina')
elif litera.upper() == 'C':
    print(f'Litera {litera} to cytozyna')
elif litera.upper() == 'G':
    print(f'Litera {litera} to guanina')
elif litera.upper() == 'T':
    print(f'Litera {litera} to tymina')
elif litera.upper() == 'U':
    print(f'Litera {litera} to uracyl')
else:
    print(f'Podałeś {litera} - błędna litera')
Podaj literę oznaczającą zasadę azotową:  a

Litera a to adenina

Kolejnym słowem kluczowym, które możemy wykorzystać jest in. Spójrz na poniższy przykład i zastanów się jak działa:

# Pobranie liczby od użytkownika
slowo = input('Podaj słowo: ')
litera = input('Podaj literę: ')

if litera in slowo:
    print(f"Litera '{litera}' znajduje się w słowie '{slowo}'")
else: 
    print(f"Litera '{litera}' nie znajduje się w słowie '{slowo}'")
Podaj słowo:  nukleotyd
Podaj literę:  t

Litera 't' znajduje się w słowie 'nukleotyd'
  • Zadanie: Spróbuj zmodyfikować program tak, żeby nie był ,,czuły'' na wielkość liter.

Operatory logiczne

Kolejny przykład będzie także nawiązywał do rozpoznawania zasad azotowych. Tym razem jednak będziemy chcieli, żeby po podaniu przez użytkownika litery, uzyskać odpowiedź, czy odpowiada ona zasadzie purynowej (A lub G) czy pirymidynowej (C, T lub U).

Spróbuj samodzielnie napisać taki program.

Zapewne będzie on wyglądał mniej więcej tak (dla uproszczenia pomijam kwestię wielkości liter):

# Program rozpoznający zasady purynowe i pirymidynowe

# Pobranie litery od użytkownika
litera = input('Podaj symbol zasady: ')

# Sprawdzenie czy litera odpowiada zasadzie purynowej, czy pirymidynowej.
if litera == 'A':
    print(f'{litera} to zasada purynowa')
elif litera == 'G':
    print(f'{litera} to zasada purynowa')
elif litera == 'C':
    print(f'{litera} to zasada pirymidynowa')
elif litera == 'T':
    print(f'{litera} to zasada pirymidynowa')
elif litera == 'U':
    print(f'{litera} to zasada pirymidynowa')
else:
    print(f'Podałeś {litera} - błędna litera')
Podaj symbol zasady:  T

T to zasada pirymidynowa

Jak widać program działa. Jednak zauważ, że zawiera kilkukrotne powtórzenia tych samych fragmentów kodu. Dla każdej z liter odpowiadającej zasadzie purynowej wykonywany jest ten sam kod: print(f'{litera} to zasada purynowa'), który jest powtórzony dwa razy, dla zasad pirymidynowych mamy trzy powtórzenia. Pojawia się pytanie czy nie można by stworzyć testu w rodzaju: ,,jeżeli litera == A LUB litera == G''? Odpowiedź na nie jest na szczęście twierdząca.

Z pomocą przychodzą na operatory logicze, które pozwalają łączyć warunki w różny sposób. Pierwszy z nich to or, który oznacza ,,lub''. Możemy teraz zmodyfikować nasz program:

# Program rozpoznający zasady purynowe i pirymidynowe

# Pobranie litery od użytkownika
litera = input('Podaj symbol zasady: ')

# Sprawdzenie czy litera odpowiada zasadzie purynowej, czy pirymidynowej.
if litera == 'A' or litera == 'G':
    print(f'{litera} to zasada purynowa')
elif litera == 'C' or litera == 'T' or litera == 'U':
    print(f'{litera} to zasada pirymidynowa')
else:
    print(f'Podałeś {litera} - błędna litera')
Podaj symbol zasady:  T

T to zasada pirymidynowa

Teraz kod jest krótszy, bardziej przejrzysty a także łatwiejszy w ewentualnej modyfikacji. Gdybym na przykład stwierdził, że zamiast komunikatu T to zasada pirymidynowa powinno się wyświetlać Litera T, oznacza zasadę pirymidynową, musiałbym zmodyfikować dwie linie kodu a nie pięć. Staraj się, na ile to możliwe, unikać zbędnych powtórzeń kodu. Wrócimy jeszcze wielokrotnie do tego zagadnienia.

Operator or łączy warunki, a zwracana jest wartość True jeśli choć jeden z nich zwraca wartość True. Można to łatwo przetestować:

wynik = False or False or True
print(wynik)
True

Następnym operatorem logicznym jest and, czyli ,,oraz''. W tym przypadku zwracana jest wartość True, jeżeli wszystkie łączone wyrażenia zwracają True:

wynik = True and True and False
print(wynik)
False

Napiszmy krótki program ilustrujący działanie operatora and. Będzie sprawdzał, czy podana liczba jest większa niż 0 i mniejsza niż 10.

# Program sprawdzający, czy podana liczba jest większa niż 0 i mniejsza niż 10

# Pobranie liczby od użytkownia
liczba = float(input('Podaj liczbę: '))

# Sprawdzanie, czy liczba jest większa niż 0 i mniejsza niż 10
if liczba > 0 and liczba < 10:
    print(f'Liczba {liczba} jest większa niż 0 i mniejsza niż 10')
else:
    print(f'Liczba {liczba} nie jest większa niż 0 i mniejsza niż 10')

Podaj liczbę:  9.9

Liczba 9.9 jest większa niż 0 i mniejsza niż 10

Operatory logiczne można łączyć ze sobą. W celu zapewnienia odpowiedniej kolejności wykonywania testów (podobnie jak w przypadku obliczeń) stosuje się pary nawiasów ( ).

Zobaczmy jak to działa na przykładzie następnego programu. Napiszemy krótki program, który rozpoznaje czy podana przez użytkownika liczba jest jednocześnie (!) parzysta, podzielna przez 3, większa niż 10 i mniejsza niż 100.

Najpierw zastanów się, jak można sprawdzić czy liczba jest parzysta.

Można tu użyć operatora %, który zwraca resztę z dzielenia. Zatem, jeśli liczba jest parzysta, wyrażenie liczba%0, powinna zwrócić 0.

Można to sprawdzić tak:

# Pobranie liczby od użytkownia
liczba = int(input('Podaj liczbę: '))

if liczba % 2 == 0:
    print(f"Liczba {liczba} jest parzysta")
else: 
    print(f"Liczba {liczba} nie jest parzysta")
Podaj liczbę:  8

Liczba 8 jest parzysta

Analogicznie sprawdzimy, czy liczba jest podzielna przez trzy. Pozostałe warunki są trywialne. Połączmy je w całość:

# Pobranie liczby od użytkownia
liczba = int(input('Podaj liczbę: '))

if liczba % 2 == 0 and liczba % 3 == 0 and liczba > 0 and liczba < 100:
    print(f"Liczba {liczba} spełnia wszystkie warunki")
else: 
    print(f"Liczba {liczba} nie spełnia wszystkich warunków")
Podaj liczbę:  66

Liczba 66 spełnia wszystkie warunki

Przetestuj program dla różnych liczb, zauważ, że wszystkie warunki muszą być spełnione, żeby całe wyrażenie zwróciło wartość true. Operator and można połączyć ze słowem kluczowym not, w takim przypadku, jak można się domyślić oznacza zaprzeczenie and. Przykładowo, kolejny program:

# Pobranie liczby od użytkownia
liczba = int(input('Podaj liczbę: '))

if liczba % 2 == 0 and not liczba % 3 ==0:
    print(f"Liczba {liczba} jest podzielna przez 2 ale nie jest podzielna przez 3")
else: 
    print(f"Liczba {liczba} nie spełnia warunków")
Podaj liczbę:  4

Liczba 4 jest podzielna przez 2 ale nie jest podzielna przez 3

Zagnieżdżanie

Instrukcje if (jak i wiele innych) można zagnieżdżać. Zobaczmy to na przykładzie mini gry przygodowej. Najpierw pobierz plik z grą, uruchom ją, zagraj kilka razy wybierając różne opcje a potem przeanalizuj kod. Przy okazji zwróć uwagę jak można podzielić długą linię tekstu na kilka krótszych:

## Mini gra przygodowa:

imie = input("Jesteś wojownikiem, który znalazł się w ciemnym lesie, który ludzie nazywają " + 
             "Smoczym Lasem. \nPodaj swoje imię: ")
sciezka = input(f"{imie}, stoisz na ścieżce, która się rozwidla, gdzie idziesz?\n" + 
                "p - w prawo, l - w lewo: ")
if sciezka == 'l':
    wybor = input("Widzisz wejście do jaskini. Wchodzisz?\n" +
                   "tak - t, nie - n :")
    if wybor == 't':
        print(f"{imie}! Znalazłeś skarb!")
    elif wybor == 'n':
        print("Szkoda...")
    else:
        print("Nie ma takiej opcji.")
elif sciezka == 'p':
    wybor = input("Widzisz wielką smoczycę. Co robisz?\n" +
                   "w - walczę, u - uciekam: ")
    if wybor == 'w':
        print(f"{imie}! To nie jest najlepszy pomysł napadać na smoczycę z gołymi rękami. " + 
              "Smoczyca Cię zjadła!")
    elif wybor == 'u':
        wybor = input("Ocaliłeś życie. Natykasz się na małego smoczka. Co robisz?\n" +
                     "o - oddaję smoczycy, b - biorę do domu, z - zostawiam w spokoju: ")
        if wybor == 'o':
            print("Smoczyca jest zachwycona, w nagrodę daje Ci worek złota.")
        elif wybor == 'b':
            imie_smoka = input("Zabrałeś smoka do domu. Ciekawe, czy to dobry pomysł? " + 
                               "Jak dałeś mu na imię?\n")
            print(f"Smok {imie_smoka} rósł w Twoim domu, towarzysząc Ci w codziennym życiu.\n" +
                 "Jednak pewnego dnia, kiedy zapomniałeś go nakarmić, zjadł Cię " +
                 "i odleciał do smoczego lasu. \n" +
                 "Morał: nie zabieraj ze sobą dzikich zwierząt.")
        elif wybor == 'z':
            print("Mądry wybór, choć może coś Cię ominęło?")
        else:
            print("Nie ma takiej opcji.")
    else:
        print("Nie ma takiej opcji. Niestety, smoczyca nie czekała na własciwą decyzję" + 
              "i Cię zjadła.")
else:
    print("Nie ma takiej ścieżki.")
print("Koniec przygody.")

Jesteś wojownikiem, który znalazł się w ciemnym lesie, który ludzie nazywają Smoczym Lasem. 
Podaj swoje imię:  Kajko
Kajko, stoisz na ścieżce, która się rozwidla, gdzie idziesz?
p - w prawo, l - w lewo:  l
Widzisz wejście do jaskini. Wchodzisz?
tak - t, nie - n : n

Szkoda...
Koniec przygody.

Jak widać, zagnieżdzając instrukcje wyboru, możemy kierować przebieg programu w różnych kierunkach, w zależności od wprowadzonych danych, wyników obliczeń itp.

Zadanie:

Napisz samodzielnie własną grę przygodową.

Last updated on 22 Oct 2020
Published on 22 Oct 2020