Trudno napisać program, który będzie realizowany zawsze sekwencyjnie od pierwszej do ostatniej linii, bez najmniejszego rozwidlenia, bez sprawdzenia warunku, bez konieczności powtarzania jakiejś grupy kodu. Te wszystkie rozwidlenia i zapętlenia służą do uproszczenia samego kodu, uczynienia kodu programu czytelniejszym, funkcjonalnym, ale przede wszystkim efektywnie wykonującym zamierzone w nim czynności. Dlatego też znajomość rozwidleń warunkowych oraz rodzajów zapętleń jest niezbędna by tworzyć dobry kod.
Spis treści
Postawmy warunki
Zapytania warunkowe służą do wybrania różnego kodu w zależności od sprawdzanego testu, naszego warunku od którego różnicujemy to co chcemy dalej w kodzie uczynić. Przykładem może być dzielenie dwu liczb a
i b
, należy sprawdzić, czy b
nie jest równe zeru przed użyciem tej zmiennej jako dzielnika. Gdy b
jest równe zeru, to przy dzieleniu zaindukuje się błąd ZeroDivisionError: division by zero.
A co Jeśli?
Taki test można wykonać tak jak w poniższym przykładzie:
a=10 b=0 if (b!=0): print("Wynik=",a/b) else: print("Próba dzielenia przez 0")
Daje nam to już poprawne działanie naszego kodu bez jego przerywania błędami.
Najprostsze warunki w arytmetyce liczb to:
Równe: a == b
Nie równe: a != b
Mniejsze: a < b
Mniejsze lub równe: a <= b
Większe: a > b
Większe lub równe: a >= b
Nie wyczerpuje to listy możliwych warunków, bo możemy w takiej konstrukcji używać testów logicznych np. sprawdzenia czy zawartość zmiennej jest liczbą całkowitą (.is_integer()
) itp.
Należy pamiętać, że syntaksa Pythona wymaga zapisania prostego warunku (tylko if i jedna komenda gdy warunek spełniony) w jednej linii, bądź, przy bardziej rozbudowanych strukturach – z wykorzystaniem wcięć (4 spacje, lub znak tabulacji).
W innym przypadku możemy użyć dodatkowego zapytania warunkowego, by rozbudować kaskadowo nasz test z wykorzystaniem elif
(a jeśli nie to czy?) tak jak poniżej.
a=10 b=5 if (type(b)==str and not b.isdigit()): print("Wartość b nie jest liczbą...") elif (b.is_integer() and b!=0): print("Wynik=",a/b) else: print("Próba dzielenia przez 0")
Ważna jest kolejność zapytań (testów), celem eliminacji niepożądanych w naszym rozumieniu typów, czy wartości zmiennej b
. Jest to uwarunkowane tym, że np. typ int nie posiada metody .isdigit()
, która to występuje w typie str. Metoda .is_integer()
została zaimplementowana w Python od wersji 3.10, dla poprzednich wersji możesz skorzystać z analogicznej metody .__int__()
. Generalnie trzeba pamiętać, że Python intensywnie się rozwija, co może powodować, że poprzednio działające metody są deprecjonowane i usuwane, a pojawiają się nowe1ma to na celu np. zastąpienie metod w których wykryto błędy bezpieczeństwa i poprzez wprowadzenie nowej (binarnie bezpiecznej z ang: binary-safe) wskazuje się, że problem został rozwiązany..
W powyższym przykładzie widoczna jest także złożona konstrukcja warunku zawierająca kwantyfikatory logiczne. Możliwymi są: and
, or
, not
.
Możliwe są konstrukcje zawierające w swym kodzie wielokrotne użycie if – takie one zwykło się nazywać zagnieżdżonymi (ang. nested).
Jeśli zaś z jakiś względów chcemy użyć pustego warunku (bez wykonywania kodu w przypadku spełnienia tego warunku) to musimy użyć dyrektywy pass
. Takie użycie przedstawione jest poniżej:
a=10 b=5 if (a==b): pass
Ciekawą konstrukcją warunku if jest poniższy przykład:
a=10 b=17 print(b-a) if (b>a) else print(a-b)
Gdzie widzimy wpierw realizację komendy print, gdy warunek będzie spełniony, a następnie jest w kodzie umieszczony tenże warunek i po else
następuje rozkaz dla alternatywy.
Wracając nieco wcześniej, zmodyfikujmy nasz program tak aby możliwe było wprowadzenie wartości interaktywnie w odpytaniu użytkownika. Do odczytu wartości z klawiatury służy komenda input
.
a=10 b=input("Podaj wartość b=") if (type(b)==str and not b.isdigit()): print("Wartość b nie jest liczbą...") else: b=int(b) if (b.is_integer() and b!=0): print("Wynik=",a/b) else: print("Próba dzielenia przez 0")
Przetestuj powyższy kod na okoliczność różnych wartości b
.
Ternary Operator (Trójargumentowe wyrażenie warunkowe)
Dla formalności jeszcze poniższy przykład do przeanalizowania. Przy krótkich warunkach i ich realizacjach można posiłkować się wygodną strukturą warunku trójargumentowego ? :
.
a = 100 b = 100 print("a większe") if a > b else print("argumenty równe") if a == b else print("b większe")
Gdy trzeba się powtórzyć
Następnymi ważnymi strukturami upraszczającymi nasz program są zapętlenia.
W zasadzie omówimy dwie wygodne konstrukcje, gdzie pierwszą już poznaliśmy w przykładach na wprowadzeniu do Pythona – jest to for
. Druga dedykowana jest wielokrotnemu powtarzaniu kodu, gdy na etapie jego tworzenia nie dekretujemy ilości powtórzeń pętli, a która to ilość może zależeć od np. warunków obliczanych lub uzyskiwanych w trakcie działania kodu w tej pętli – jest to while
.
For (in)
Jak już wspomnieliśmy ten rodzaj zapętlenia bazuje na założeniu, że z zasady (choć niekoniecznie z liczby) znamy ilość powtórzeń kodu. Do tej pory wykorzystywaliśmy for
do przemierzania po istniejących listach, aby niejako zaciągać do pętli poszczególne elementy listy. W takim przypadku możemy na etapie pisania kodu nie znać rozmiaru takiej listy, ale zakładać, że pętla ma się wykonać dla każdego jej elementu. Tutaj więc kwestię określenia liczności zbioru zrzucamy na komputer (i słusznie – on liczy najlepiej).
Przeanalizujmy zatem różne wersje użycia tej pętli…
samochody = ["Audi", "Chevrolet", "Mercedes"] for x in samochody: print(x)
Jest to w zasadzie analogiczne do bardziej rozbudowanego przykładu z poprzedniego tematu:
list=(("Kowalski","Jan",2008),("Konstantynowiczówna","Wierzchosława",1956),("Antecki","Wojciech",1987),("Magdziarz","Marek",1999),("Wolny","Maciej",2003),("Burda","Wiktoria",2007)) maxlength=0 for i in list: for ii in i: if maxlength<len(str(ii)): maxlength=str(ii).__len__() for i in list: for ii in i: print(ii.__format__(" <%d" % maxlength),end=" | ") print()
Inną wersją jest deklaracja ilości powtórzeń korzystając z klasy range()
.
for x in range(10): print(x)
W takim przypadku zostanie stworzona struktura iteratora i pętla powtórzy się dokładnie tyle razy ile założymy2nie do końca 😉 – wyjaśnienie będzie już niebawem.
Gdy chcemy aby iterator przyjął konkretne i potrzebne nam wartości, możemy wywołać to tak:
for x in range(5,10): print(x)
Trzeba pamiętać, że podobnie jak w indeksach iterator przyjmuje najmniejszą możliwą wartość, a drugi parametr jest użyty do określenia odcięcia3limes, granica i nie zostanie ta wartość nigdy osiągnięta. W powyższym przypadku iterator zacznie się wartością 5 i osiągnie największą wartość równą 9: 5 6 7 8 9
<- 5 elementów, 5 powtórzeń pętli.
Możemy również zażyczyć sobie, aby iteracje postępowały z przyrostem większym niż standardowo 1. Wtedy musimy określić jaki interesuje nas krok, tak jak poniżej:
for x in range(1,100,2): print(x)
Break, Continue, Pass
Dodatkowymi elementami sterującymi zachowaniem pętli są polecenia:
- break – kończące wykonywanie pętli i przekazujące sterowanie do pierwszej instrukcji po kodzie pętli,
- continue – przerywające bieżące wykonanie pętli4iterację i powracające na jej początek,
- pass – kończące pustą pętlę, gdy z jakichś względów koniecznie chcemy użyć jej bez wskazywania sekwencji kodu do wykonania5Wbrew pozorom nie jest to bezsensowne.
Przykłady takiego sterowania są pokazane poniżej:
#Drukujemy liczby parzyste w zakresie od 0 do 10 for x in range(10): if (int(x/2)==x/2): print(x) #To samo co powyżej, ale z wykorzystaniem continue for x in range(10): if (int(x/2)!=x/2): continue print(x)
While
Pętla while wykorzystywana jest do wykonania kodu tak długo jak jest prawdziwy stawiany jej warunek. To znaczy, że zanim choć raz wykonamy kod w pętli to wpierw sprawdzimy czy warunek jej wykonania jest spełniony. Ma to znaczenie w wielu sytuacjach, gdzie np. próba odczytu z pliku, gdy plik nie jest otwarty do odczytu spowodowałaby wygenerowanie błędu i nieoczekiwane, nagłe zakończenie naszego programu.
Konstrukcja pętli while może mieć poniższą postać:
i=1 while i<10: print(i) i+=1
Powyżej jednak zadeklarowaliśmy ilość powtórzeń w sposób jawny, więc odtworzyliśmy zachowanie pętli for… ale już w poniższym przypadku mamy właściwy przykład użycia tego rodzaju pętli:
password="" while password=="": password=input("Podaj hasło:") if (password.__eq__("Ala")): break else: print("To nie jest właściwe hasło! Spróbuj jeszcze raz...") password=""
W tym przypadku program tak długo będzie się pytał o właściwe hasło, dopóki go nie podamy… Oczywiście w “realnym świecie” raczej po 3-5 pytaniach o hasło powinniśmy zablokować dostęp do kontynuacji programu, ale to już zagadnienie na inne rozważania.
Niejako przy okazji wyszło nam jedno ważne zagadnienie, a mianowicie porównanie dwu obiektów – tutaj obiektu zmiennej password oraz obiektu nienazwanej zmiennej tymczasowej przyjmującej w naszym programie wartość chwilową “Ala“. W przypadku porównania obiektów winniśmy używać metody .__eq__()6equal === równa się, zamiast ==
, aby zapewnić poprawne porównanie tych obiektów. Akurat w przypadku typów str, komputer “domyśli się”7owe “domyślenie się” wynika właśnie z faktu zdefiniowania w definicji klasy metod .__eq__()
itd. Dlatego zachęcam do stosowania z wyboru metod, by być świadomym tego faktu. Jeśli danych metod nie ma zdefiniowanych, to obiekt stworzony na podstawie takiej klasy nie będzie obsługiwał prawidłowo porównań z wykorzystaniem notacji arytmetycznej. Powstrzymuję się tutaj od wnikliwego zajrzenia w konstrukcję i definicję klasy zostawiając to na późniejsze zajęcia. , ale nie jest to już takie oczywiste w innych momentach. Dla porównywania wartości obiektów dedykowane są metody:
- __eq__() – equal (równe),
- __ne__() – not equal (nie równe)
- __gt__() – greater then (większe),
- __ge__() – greater or equal (większe lub równe),
- __lt__() – less then (mniejsze),
- __le__() – mniejsze lub równe.
Zadania do przećwiczenia materiału
A Switch/Case gdzie się podziało?
Cóż, znana z innych języków struktura pozwalająca na podejście proceduralnego wywoływania w zależności od wartości parametru, w języku Python do wersji 3.10 nie istniała i należało stosować poznaną dziś strukturę elif.
wiek=int(input("Podaj Twój wiek: ")) if wiek > 90: print("Babciu, czy się nie zpóźniłaś na zabawę??") elif wiek < 0: print("Chyba się jeszcze nie urodziłeś lol...") elif wiek >= 18: print("Zapraszam na imprezę") else: print("Jesteś za młody by balować...")
Od wersji Python 3.10 zaimplementowana została możliwość tzw.: structural pattern matching, co umożliwia zaprojektowanie niejako od podstaw metody switch/case tak jak poniżej:
parametr=input("Jaki język programowania znasz? ") match parametr: case "JavaScript": print("Możesz zostać webdeweloperem.") case "PHP": print("Możesz programować backend") case "Python": print("To wymarzony język do przeszukiwania danych") case "Solidity": print("Znasz się na Blockchain") case"Java": print("Możesz pisać aplikacje mobilne") case _: print("nie wiem co ze sobą możesz zrobić... naucz się czegoś!")
Należy jednak zauważyć, że możemy projektować nasze własne procedury, które nawet w nieco klasyczny, jak na Pythona, sposób podchodzą do metody wyboru:
parametr=input("Jaki język programowania znasz? ") def switch(parametr): if parametr.__eq__("JavaScript"): return "Możesz zostać webdeweloperem." elif parametr.__eq__("PHP"): return "Możesz programować backend" elif parametr.__eq__("Python"): return "To wymarzony język do przeszukiwania danych" elif parametr.__eq__("Solidity"): return "Znasz się na Blockchain" elif parametr.__eq__("Java"): return "Możesz pisać aplikacje mobilne" else: return "nie wiem co ze sobą możesz zrobić... naucz się czegoś!" print(switch(parametr)) #lub: print(switch("PHP")) print(switch("Java"))
Zadania
Przejdźmy do zadań utrwalających zdobyte wyżej umiejętności. Korzystając z dwu dodatkowych tematów zapoznaj się z możliwą obsługą liczb pseudolosowych oraz obsługą daty.
Grupę zadań podstawowych przedstawionych do implementacji w niniejszym temacie można znaleźć w Podstawach Programowania8Hasło to: Java2020!!!.
Zadanie 1
Napisz program realizujący zadanie kostki do losowania – spróbuj wyświetlić wylosowaną liczbę w symulacji wyglądu kostki np dla liczby 5:
Zadanie 2
Napisz program pytający o datę urodzin, a następnie wyświetlający liczbę dni, która pozostała do najbliższych urodzin.
Zadanie 3
Napisz program wypisujący dowolną liczbę (wprowadzoną poprzez
input
) w postaci matrycowej zaprezentowanej poniżej (format “czcionki” wedle uznania):