Wyzwanie Python #2: Podstawowe instrukcje!

Maciej Bartoszuk 21 lutego 2023
 

Gdy pierwsze kroki mamy już za sobą i umiemy uruchomić nasz pierwszy program, czas zapoznać się z podstawowymi instrukcjami, jakich możemy użyć w języku Python. Będzie to podstawa, na której będziemy mogli budować dalsze, bardziej skomplikowane programy.

Komentarze

Zanim przejdziemy do konkretnych instrukcji, warto wspomnieć, czym jest komentarz w kodzie. Jest to wydzielony fragment kodu, który nie jest w żaden sposób interpretowany przez interpreter języka Python. Ma on służyć jedynie człowiekowi, aby kod był czytelniejszy. Zazwyczaj jest to skomentowanie mniej oczywistych partii kodu, informacja o tym, do czego służy dana funkcja, czy po prostu wyłączenie wiersza kodu, którego chwilowo nie chcemy wykonywać.

Język Python dopuszcza dwa rodzaje komentarzy: jedno- oraz wielowierszowe. Te pierwsze zaczynamy znakiem #. Od tego znaku aż do końca wiersza kod nie jest interpretowany. Dobry zwyczaj nakazuje zostawienie jednego znaku odstępu (spacji) pomiędzy tym znakiem a początkiem tekstu komentarza.

# funkcja główna programu
def main():
    print("Witaj świecie!") # ta funkcja wypisuje napis
    # wiersz poniżej wczytuje dane z klawiatury
    pobrany_napis = input()
    print("Twój napis to: " + pobrany_napis)
# uruchomienie funkcji głównej
if __name__ == "__main__":
    main()

Istnieje też komentarz wielowierszowy. Ten zaczyna się od trzech znaków ": """. Tak naprawdę zapis ten tworzy napis wielowierszowy (o samych napisach będziemy jeszcze pisać), ale są one (te napisy) używane także do obszerniejszych komentarzy.

"""
Tutaj następuje obszerne wyjaśnienie funkcji main().
Przyjmowane parametry: żadne
Wartość zwracana: żadna
"""
def main():
    print("Witaj świecie!")
    pobrany_napis = input()
    print("Twój napis to: " + pobrany_napis)
if __name__ == "__main__":
    main()

Oczywiście możemy w ramach jednego kodu źródłowego dowolnie używać na przemian obu typów komentarzy.

Zmienne

W naszych programach często będziemy obliczać jakieś wartości lub wczytywać je od użytkownika. Jednak samo obliczenie wartości to nie wszystko. Trzeba jeszcze ją gdzieś zapisać, aby wynik ciężkiej pracy procesora nie poszedł na marne. Gdy ją zapiszemy, możemy z niej skorzystać wielokrotnie, bez ponownego jej obliczania. Aby to zrobić, musimy posłużyć się zmienną. Zmienna często jest przyrównywana do pudełeczka. Co więcej, pudełeczko ma swoją etykietę. To właśnie po tej etykiecie odwołujemy się do niego w dalszej częsci programu. Podsumowując, ważnym jest, żeby rozróżniać dwie rzeczy: nazwę zmiennej (etykietę pudełka) i jej wartość (wnętrze pudełka). Przykładowo:

a = 7

Powyżej mamy zmienną o nazwie a, która ma wartość 7. Pamiętajmy, że zmienna, jak sama nazwa wskazuje, może zmieniać swoją wartość w czasie trwania programu:

a = 7
print(a)
## 7
a = 8
print(a)
## 8

Teraz omówmy styl nazewnictwa zmiennych. Jest to wbrew pozorom dość ważne zagadnienie, które mocno wpływa na czytelność kodu, a więc także na koszt jego utrzymania w przyszłości (np. czy łatwo jest zmodyfikować kod w przyszłości, gdy zapomnimy, co dokładnie w nim napisaliśmy lub pracujemy na cudzym kodzie).

Zacznijmy od tego, jakie znaki mogą składać się na nazwę zmiennej. Otóż jest to zdefiniowane w dokumentacji do języka: mogą to być małe i wielkie litery od a do z, znak podkreślenia _, a także cyfry od 0 do 9, przy czym nazwa zmiennej nie może się od cyfry zaczynać (może za to od litery i znaku podkreślenia).

Gdy już wiemy, jakie znaki może zawierać identyfikator zmiennej, przede wszystkim zapamiętajmy zasadę: komentarz jest zawsze złym rozwiązaniem i należy go w miarę możliwości unikać. Za to dobrym rozwiązaniem jest takie nazywanie zmiennych i funkcji, aby te nazwy same w sobie tłumaczyły, co kod robi. Tak więc złym rozwiązaniem jest:

p = 0.23 # podatek VAT

zaś dobrym:

podatek_VAT = 0.23

Ponieważ i tak nie musimy pisać nazwy zmiennej w całości, a wystarczy napisać jedynie jej początek, a środowisko programistyczne podpowie nam i uzupełni resztę, nie bójmy się nawet dość długich nazw zmiennych:

podatek_VAT_do_2010 = 0.22
podatek_VAT_od_2011 = 0.23

Jak widzimy, dłuższe nazwy zmiennych powodują pewien kłopot: jak łączyć poszczególne składowe takiej nazwy? Wyróżniamy parę typowych sposobów:

  • b (pojedyncza mała litera)

  • B (pojedyncza wielka litera)

  • lowercase (małe litery)

  • lower_case_with_underscores (małe litery z podkreśleniami)

  • UPPERCASE (wielkie litery)

  • UPPER_CASE_WITH_UNDERSCORES (wielkie litery z podkreśleniami)

  • CapitalizedWords (lub CapWords czy CamelCase – nazwane tak od “garbów” jakie tworzą wielkie litery). Uwaga: Podczas używania akronimów w tym stylu, używamy wielkich liter dla całego akronimu, stąd napiszemy: HTTPServerError, a nie: HttpServerError.

  • mixedCase (tak jak poprzednio, ale zaczynamy małą literą)

  • Capitalized_Words_With_Underscores (brzydki, nieużywany sposób)

Więcej o nazewnictwie można przeczytać tutaj.

Którego sposobu używać? Tak naprawdę odpowiedź jest następująca: wszystko jedno którego, byle konsekwentnie. Jednak gdy wczytamy się w dokumentację Pythona, znajdziemy informację, że polecanym sposobem dla zmiennych oraz funkcji jest używanie małych liter oraz znaku podkreślenia (lower_case_with_underscores). Niektóre firmy tworzą swoje własne konwencje nazewnicze dla danego języka, jak np. Google.

Pozostaje jeszcze odpowiedzieć na pytanie, w jakim języku tworzyć nazwy zmiennych. W tym poradniku, dla celów dydaktycznych, nazwy zmiennych będą w języku polskim, aby nie zniechęcać osób (być może jeszcze bardzo młodych), które nie znają języka angielskiego, a chcą uczyć się programować. Jednak w praktyce, w firmach, nawet całkowicie polskich, programuje się w języku angielskim (w tym języku nazywa się zmienne i funkcje). Po pierwsze nie występuje wtedy problem z odmianą słów przez przypadki, a po drugie nigdy nie wiadomo, kiedy w dobie powszechnej globalizacji dojdzie do zespołu osoba, która nie posługuje się językiem polskim.

Typy danych

Każda zmienna, albo, mówiąc ogólniej, każda wartość w programie, ma swój typ. Są liczby całkowite, zmiennopozycyjne, zespolone, napisy, wartości logiczne… Jednak, w odróżnieniu od takich języków jak C++, C# czy Java, w języku Python występuje typowanie dynamiczne. Oznacza to, że konkretny identyfikator, konkretna zmienna, np. a, może raz przechowywać napis ("Ala ma kota") by po chwili przechowywać liczbę całkowitą (3). W niektórych językach programowania jest to nie do pomyślenia, jednak Python ceni wolność programisty w tym względzie, by go sztucznie nie ograniczać (oczywiście dzieje się to pewnym kosztem: trudniej analizuje się programy, w których nie możemy mieć pewności, na jakich danych operujemy). Do sprawdzania typu danych służy funkcja type().

I tak najważniejszymi typami w języku Python są:

  • bool, wartość logiczna, tak lub nie, prawda (True) albo fałsz (False):
logiczna = True
print(type(logiczna))
## <class 'bool'>
  • int, liczba całkowita, np. -7, 0 czy 3:
calkowita = -7
print(type(calkowita))
## <class 'int'>
  • float, czyli wartość zmiennopozycyjna, można ją utożsamiać z wartościami rzeczywistymi, np. -0.67, 1.0, 3.14:
zmiennopozycyjna = -7.4
print(type(zmiennopozycyjna))
## <class 'float'>
  • complex, czyli liczba zespolona, np. -7+8.5j. Warto pamiętać, że w Pythonie jednostką urojoną jest j, a nie i.
zespolona = -7.4+8.4j
print(type(zespolona))
## <class 'complex'>
  • str, powszechnie znany w innych językach jako string, czyli napis. Napis poznajemy głównie po tym, że jest zapisany w cudzysłowie (i to odróżnia go choćby od nazwy zmiennej czy liczby, które nie są w cudzysłowach). Dodamy, że w języku Python nie ma znaczenia, czy posługujemy się pojedynczymi (') czy podwójnymi (") cudzysłowami:
napis = "6+7j" # równie dobrze "ala ma kota"
print(type(napis))
## <class 'str'>

Konwersje typów

Często zachodzi potrzeba konwersji typów, w szczególności z lub do napisowego. Do tego służą funkcje, które nazywają się dokładnie tak, jak typy. Przyjrzyjmy się prostej konwersji z int na float:

print(float(5))
## 5.0

Jak widzimy całkowite 5 (bez kropki ani zera po niej) zostało przekonwertowane na zmiennopozycyjne 5.0. Możemy też dokonać konwersji w drugą stronę:

print(int(5.0))
## 5

Co jednak się stanie, gdy spróbujemy przekonwertować liczbę, która ma niezerową część ułamkową?

print(int(5.7))
## 5

Jak widzimy, zostanie ona ucięta, niezależnie od tego, czy było jej bliżej do kolejnej liczby całkowitej czy poprzedniej. Tak samo dla liczb ujemnych:

print(int(-5.7))
## -5

Przyjrzyjmy się teraz konwersjom dotyczących napisów. Z napisu do liczby (przypomnijmy, że napisy poznajemy po cudzysłowach):

print(float("-5.3"))
## -5.3

A także z liczby do napisu:

napis = str(-5.3)
print(napis)
## -5.3
print(type(napis))
## <class 'str'>

Niestety podczas wypisywania napisu jest to robione bez cudzysłowów, dlatego dla pewności dodaliśmy sprawdzenie typu.

Konwersji z napisu na liczbę będziemy dokonywać podczas używania funkcji input(), np. gdy będziemy wczytywać liczbę od użytkownika, a konwersji na napis, gdy będziemy chcieli połączyć (dokonać konkatenacji) napis z liczbą (liczbę trzeba przekonwertować najpierw na napis).

Operatory

Gdy wiemy już, jakie typy danych możemy przechowywać, czas dokonać pierwszych operacji na nich!

Podstawowe operatory arytmetyczne

Język Python udostępnia typowe operacje znane z lekcji matematyki:

  • dodawanie (+)
  • odejmowanie (-)
  • mnożenie (*)
  • dzielenie (/)
  • reszta z dzielenia, modulo (%)

Napiszmy prosty program, ilustrujący użycie tych operatorów:

def main():
    x = 7
    y = 3
    
    suma = x + y
    print("Dodawanie: " + str(suma))
    
    roznica = x - y
    print("Różnica: " + str(roznica))
    
    iloczyn = x * y
    print("Iloczyn: " + str(iloczyn))
    
    iloraz = x / y
    print("Iloraz: " + str(iloraz))
    
    reszta = x % y
    print("Reszta z dzielenia: " + str(reszta))
    
if __name__ == "__main__":
    main()
## Dodawanie: 10
## Różnica: 4
## Iloczyn: 21
## Iloraz: 2.3333333333333335
## Reszta z dzielenia: 1

Zwróćmy uwagę na str(). Jest to funkcja konwertująca podany argument (w naszym wypadku wynik operacji matematycznej, który jest liczbą) na napis. Czemu jest to potrzebne? Otóż + którym łączymy napis, np. "Reszta z dzielenia: ", z wynikiem działania, potrzebuje, aby oba argumenty były napisami. O ile pierwszy jest z definicji, o tyle drugi jest liczbą, którą dopiero trzeba przekonwertować na napis, aby typy się zgadzały.

Operatory łączone

Czasami zachodzi potrzeba, aby zmodyfikować wartość zmiennej na podstawie dotychczasowej wartości w niej przechowywanej. Wyobraźmy sobie, że mamy 3 ziemniaki w garnku. Teraz chcemy dodać jeszcze 2 nowe ziemniaki do garnka (gdyż właśnie teściowa zapowiedziała nam się na obiad). Na podstawie dotychczasowej wiedzy moglibyśmy napisać:

ziemniaki_w_garnku = 3
ziemniaki_w_garnku = ziemniaki_w_garnku + 2
print(ziemniaki_w_garnku)
## 5

Jednak taki zapis jest dość barokowy, a potrzeba dość częsta, dlatego możemy równie dobrze napisać:

ziemniaki_w_garnku = 3
ziemniaki_w_garnku += 2
print(ziemniaki_w_garnku)
## 5

Operator += jest operatorem, który modyfikuje zmienną stojącą po lewej stronie, dodając do jej dotychczasowej wartości wartość stojącą po prawej stronie. Analogicznie mamy operatory -=, *=, /=, %=.

Warto przy okazji zaznaczyć, że w języku Python, w przeciwności do wielu innych popularnych języków, nie występuje operator ++, zwiększający wartość zmiennej o 1. Stąd trzeba pisać zmienna += 1.

Operatory porównań

Przejdźmy teraz do operatorów porównań. Można je postrzegać dokładnie tak samo, jak operatory arytmetyczne, takie jak dodawanie, jednak ich wynikiem są wartości logiczne, tj. prawda (True) albo fałsz (False). I tak zacznijmy od prostego przykładu:

logiczna = 4 < 5
print(logiczna)
## True

oraz:

logiczna = 6 >= 10
print(logiczna)
## False

Jak widzimy, operatory < (mniejsze) czy >= (większe równe) sprawdzają relację pomiędzy dwoma liczbami i zwracają wartość logiczną, czy sprawdzana relacja zachodzi. Oczywiście ma to większy sens, gdy argumentami są zmienne, których wartości nie są nam znane na etapie pisania programu (bo np. wczytujemy je od użytkownika z klawiatury).

Oto lista operatorów logicznych w języku Python:

  • < - mniejsze
  • <= - mniejsze równe, zwróćmy uwagę, że zapisujemy tak jak czytamy, nie ma operatora =< (równe mniejsze)
  • > - większe
  • >= - większe równe
  • == - równa się. Tutaj bardzo ważne jest, aby odróżniać operator przypisania (=) od operatora porównania równa się (==). To bardzo częsty błąd wśród początkujących programistów. Operator = nie jest symetryczny, ma na celu przekopiowanie wartości z prawej do lewej. W niektórych językach zapisuje się go jako <- (ale nie w Pythonie). Operator = nie ma nic wspólnego z wartościami logicznymi. Za to operator == jest operatorem zwracającym wartość logiczną, a co więcej, jest on operatorem symetryczym (nie ma znaczenia zamienienie kolejnością argumentów).
  • != - nie równa się

Napiszmy prosty kod, który zilustruje działanie poszczególnych operatorów:

def main():
    x = 7
    y = 3
    
    print(str(x) + "<" + str(y) + " == " + str(x < y))
    print(str(x) + "<=" + str(y) + " == " + str(x <= y))
    print(str(x) + ">" + str(y) + " == " + str(x > y))
    print(str(x) + ">=" + str(y) + " == " + str(x >= y))
    print(str(x) + "==" + str(y) + " == " + str(x == y))
    print(str(x) + "!=" + str(y) + " == " + str(x != y))
if __name__ == "__main__":
    main()
## 7<3 == False
## 7<=3 == False
## 7>3 == True
## 7>=3 == True
## 7==3 == False
## 7!=3 == True

To, co nowe w tym kodzie, to wielokrotne sklejanie napisów: najpierw konwertujemy x do napisu, potem doklejamy napis reprezentujący relację logiczną (np. "<="), następnie skonwertowaną do napisu wartość y, by ostatecznie dokleić wynik działania danego operatora.

Łączenie wielu operatorów

Specyficzną dla języka Python możliwością jest sprawdzenie dwóch relacji naraz. Może się to przydać np. do sprawdzenia, czy liczba należy do zadanego przedziału:

wiek = 35
czy_wiek_produkcyjny = 18 <= wiek <= 65
print(czy_wiek_produkcyjny)
## True

Operatory logiczne

Pozostaje nam jeszcze omówić parę operatorów logicznych, czyli takich, których argumentami są wartości logiczne oraz ich wynik także jest taką wartością. Są to znane nam z lekcji logiki operatory koniunkcji (and), alternatywy (or), a także zaprzeczenie (not).

  • Operator koniunkcji, and, utożsamiany z polskim i. Zwraca wartość True wtedy i tylko wtedy, gdy oba argumenty są równe True:
print("1 i 1: " + str(True and True))
## 1 i 1: True
print("0 i 1: " + str(False and True))
## 0 i 1: False
print("1 i 0: " + str(True and False))
## 1 i 0: False
print("0 i 0: " + str(False and False))
## 0 i 0: False
  • Operator alternatywy, or, utożsamiany z polskim lub. Zwraca wartość True wtedy i tylko wtedy, gdy przynajmniej jeden argument jest równy True:
print("1 lub 1: " + str(True or True))
## 1 lub 1: True
print("0 lub 1: " + str(False or True))
## 0 lub 1: True
print("1 lub 0: " + str(True or False))
## 1 lub 0: True
print("0 lub 0: " + str(False or False))
## 0 lub 0: False
  • Operator zaprzeczenia, not, utożsamiany z polskim nie. Zwraca wartość przeciwną, niż argument:
print("nie 1: " + str(not True))
## nie 1: False
print("nie 0: " + str(not False))
## nie 0: True

Przykładowe użycie: gdybyśmy nie wiedzieli, że przynależność do zbioru możemy sprawdzić poprzez połączenie dwóch operatorów relacyjnych, to moglibyśmy go dokonać w ten sposób:

wiek = 35
czy_wiek_produkcyjny = 18 <= wiek and wiek <= 65
print(czy_wiek_produkcyjny)
## True

Instrukcja warunkowa

W programie często musimy obsłużyć następujący scenariusz: wykonać kod, ale tylko pod jakimś warunkiem, w przeciwnym wypadku albo nie robić nic, albo wręcz wykonać zgoła odmienny kod. W takim celu stosujemy instrukcję warunkową if. Spójrzmy na najprostszy przykład:

wiek = 35
if wiek >= 18:
    print("osoba jest pełnoletnia")
## osoba jest pełnoletnia

Spójrzmy, co stanie się, gdy warunek nie będzie spełniony:

wiek = 15
if wiek >= 18:
    print("osoba jest pełnoletnia")

Nie wypisze się nic, ponieważ warunek nie jest spełniony. Ogólnie możemy powiedzieć, że instrukcja warunkowa ma postać:

if warunek:
    instrukcja1
    instrukcja2

Zwróćmy uwagę na to, że warunek nie jest zamknięty w okrągłych nawiasach (w przeciwności do większości języków programowania), a instrukcje znajdujące się w instrukcji warunkowej są wcięte, tak jak pisaliśmy o tym w pierwszym wyzwaniu. Oczywiście warunek może korzystać z dobrodziejstw wszystkich operatorów porównania oraz logicznych, które przedstawiliśmy wcześniej.

Co, gdy chcemy wykonać pewien kod, gdy warunek nie jest spełniony? Wtedy z pomocą przychodzi nam słowo kluczowe else:

if warunek:
    instrukcja1
    instrukcja2
else: # kod poniżej wykona się, gdy warunek nie będzie spełniony
    instrukcja3
    instrukcja4

I tak, w naszym przykładowym programie dla sklepu monopolowego otwartego całą dobę byłoby to:

wiek = 15
if wiek >= 18:
    print("osoba jest pełnoletnia")
else:
    print("osoba jest niepełnoletnia")
## osoba jest niepełnoletnia

Jednak to jeszcze nie koniec! W języku Python, w przeciwności do innych języków programowania, istnieje specjalna konstrukcja, gdy chcemy obsługiwać więcej, niż 3 przypadki:

if warunek:
    instrukcja1
    instrukcja2
elif warunek2: # gdy warunek nieprawdziwy, sprawdz warunek2
    instrukcja3
    instrukcja4
elif warunek3: #gdy warunek2 nieprawdziwy, sprawdz warunek3
    instrukcja5
    instrukcja6
else: #gdy zaden z warunkow nie byl prawdziwy
    instrukcja7
    instrukcja8

Tym razem przeniesiemy się w realia Stanów Zjednoczonych:

wiek = 19
if wiek >= 21:
    print("osoba może pić alkohol i posiadać broń")
elif wiek >= 18:
    print("osoba może pić alkohol")
else:
    print("osoba nie może pić alkoholu ani posiadać broni")
## osoba może pić alkohol

Pętle

Programowanie w dużej mierze opiera się na uogólnianiu rozwiązań problemów. Chodzi o to, aby napisać jeden kod, który rozwiązuje jak najwięcej możliwych problemów. Przykładem niech będzie obliczanie średniej ocen w szkole: chcemy napisać program, który będzie umiał obliczyć średnią niezależnie od liczby ocen, z których ją wyciągamy: nie chcemy kodu, który “na sztywno” zawsze oblicza ją z 3 czy 5 liczb, ale z n liczb. Wiąże się z tym zagadnieniem problem powtarzania kodu: możemy napisać 5 razy pod rząd kod, który prosi o liczbę użytkownika, a następnie dodaje ją do sumy. Jednak jest to dokładnie tym, czego chcemy uniknąć. W końcu mamy tu pewne powtórzenie: za każdym razem prosimy o liczbę i za każdym razem dodajemy tę liczbę do sumy. Czy nie można kazać programowi wykonywać tych dwóch czynności wielokrotnie? Np. pieć razy? siedem? Właśnie w tym celu wymyślono pętle: aby nakazać programowi wykonywać ten sam lub bardzo podobny (różniący się jedynie wartościami poszczególnych zmiennych) kod wiele razy.

Zanim przejdziemy do średniej, spójrzmy na klasyczny przykład wypisywania kolejnych liczb, od 0 do 9, który pozwoli nam zrozumieć pętle. W języku Python mamy dwa rodzaje pętli: for oraz while. Najpierw przyjrzyjmy się pętli for:

for i in range(0, 10):
    print(i)
## 0
## 1
## 2
## 3
## 4
## 5
## 6
## 7
## 8
## 9

Taki zapis oznacza, że ciało pętli (wcięte wiersze kodu pod słowem for) będą wykonywać się 10 razy: za każdym razem wartość zmiennej i będzie różna: najpierw będzie to 0, potem 1, potem 2 i tak aż do 9 włącznie. Tutaj kod nie robi nic poza wypisaniem wartości zmiennej i na ekran. Przyjrzyjmy się dokładnie: pierwszy argument funkcji range() jest podany włącznie (i przyjmie wartość 0), podczas gdy drugi wyłącznie (i nie przyjmie wartości 10, ale jedynie 9). Choć początkowo jest to nieintuicyjne, przekonamy się w przyszłości, że w wielu zastosowaniach takie podejście jest wygodniejsze.

Tak naprawdę for jest odpowiednikiem foreach znanym z innych języków. Jednak jeśli nie masz doświadczeń z tymi językami, na razie taki poziom zrozumienia w zupełności nam wystarczy.

Spójrzmy teraz na pętlę while:

i = 0
while i < 10:
    print(i)
    i+=1
## 0
## 1
## 2
## 3
## 4
## 5
## 6
## 7
## 8
## 9

Tutaj logika jest nieco inna, choć sam efekt ten sam. Stworzyliśmy zmienną i wcześniej, przypisując jej wartość 0. Następnie w samej pętli while jest warunek: wykonuj ciało pętli (kod wcięty pod słowem while) dopóki wartość zmiennej i jest ostro mniejsza od 10 (w matematyce mówimy ostro gdy chcemy podkreślić, że nie dopuszczamy równości). Dopóki więc ten warunek jest spełniony, wykonujemy dwa polecenia: wypisujemy wartość zmiennej i, oraz dodajemy do niej liczbę 1. Widzimy tu dwie różnice względem pętli for: nie podajemy z góry, jakie wartości ma przyjmować zmienna i. Za to podajemy warunek logiczny, jak długo pętla ma się wykonywać. Za to musimy sami zadbać o zmianę wartości w zmiennej i, tak aby ostatecznie warunek stał się fałszywy. Na zmienną, która się zmienia w każdej iteracji pętli (iteracja to jedno wykonanie ciała pętli, potocznie mówi się obrót), w naszym przypadku i, mówi się zmienna iterująca.

Przejdźmy teraz do przykładu z średnią. Najpierw wersja z pętlą for:

def main():
    print("Podaj liczbę ocen, które będą wchodzić w skład średniej")
    liczba_ocen = int(input())
    suma = 0
    
    for i in range(1, liczba_ocen+1):
        print("Podaj ocenę " + str(i))
        ocena = float(input())
        suma += ocena
    
    print("Suma ocen to " + str(suma))
    print("średnia ocen to " + str(suma/liczba_ocen))
    
if __name__ == "__main__":
    main()

Najciekawszymi aspektami tego rozwiązania jest konwersja wczytanego napisu (poprzez input() do liczby całkowitej przez int()), a także ustalenie zakresu pętli: tym razem zaczęliśmy od 1 (żeby nie straszyć użytkownika oceną zerową) i w związku z tym górną granicą jest liczba_ocen+1, ponieważ jest to granica wyłączna. W samej pętli wczytywane napisy konwertujemy do liczb zmiennopozycyjnych, aby móc uwzględnić oceny typu 3.5 i inne “z ułamkiem”.

Teraz przyjrzyjmy się analogicznemu kodowi z pętlą while:

def main():
    print("Podaj liczbę ocen, które będą wchodzić w skład średniej")
    liczba_ocen = int(input())
    suma = 0
    i = 1
    while i <= liczba_ocen:
        print("Podaj ocenę " + str(i))
        ocena = float(input())
        suma += ocena
        i += 1
    print("Suma ocen to " + str(suma))
    print("średnia ocen to " + str(suma / liczba_ocen))
if __name__ == "__main__":
    main()

Tym razem pozwoliliśmy sobie na nieostrą nierówność, aby zmienna i mogła przyjąć wartość równą liczba_ocen. Poza tym kod jest analogiczny do poprzedniego, z tą różnicą, że inicjujemy zmienną iterującą przed pętlą, a na końcu jej ciała zwiększamy wartość i o jeden.

Pozostaje pytanie, którą pętlę wybrać, skoro są one tak podobne? W tym momencie może być trudno mieć jakąś intuicję, jednak generalna zasada jest następująca: pętli while używa się wtedy, gdy nie jesteśmy w stanie na etapie pisania programu powiedzieć, ile będzie iteracji pętli, gdyż ta liczba jest mocno zależna od danych wejściowych (algorytmy numeryczne, wczytywanie danych z nieznanych źródeł…), podczas gdy pętla for jest używana, gdy możemy powiedzieć, ile będzie iteracji, nawet jeśli ta odpowiedź wynosi “długość tablicy”, albo “wartość zmiennej n”.

Słowo kluczowe continue

Czasami zachodzi potrzeba pominięcia konkretnej iteracji pętli. W tym celu służy instrukcja continue. Gdy ją wykonamy, wracamy do sprawdzenia warunku pętli (pętla while) lub też zmienna iterująca przyjmuje kolejną wartość (pętla for). Zazwyczaj instrukcję continue zapisujemy w instrukcji warunkowej. Rozbudujmy poprzedni przykład, poprzez pomijanie liczb ujemnych w naszym programie (wszak oceny nie mogą być ujemne i są zapewne błędem użytkownika).

def main():
    print("Podaj liczbę ocen, które będą wchodzić w skład średniej")
    liczba_ocen = int(input())
    suma = 0
    i = 1
    while i <= liczba_ocen:
        print("Podaj ocenę " + str(i))
        ocena = float(input())
        if ocena < 0:
            continue
        suma += ocena
        i += 1
    print("Suma ocen to " + str(suma))
    print("średnia ocen to " + str(suma / liczba_ocen))
if __name__ == "__main__":
    main()

Jak widzimy, program prosi o daną ocenę, aż nie otrzyma wartości nieujemnej.

Słowo kluczowe break

Drugim słowem kluczowym używanym w pętlach jest break. Służy ono do przerwania całej pętli. Tym razem napiszmy program, który będzie przerywał sumowanie, gdy napotka liczbę ujemną:

def main():
    print("Podaj liczbę ocen, które będą wchodzić w skład średniej")
    liczba_ocen = int(input())
    suma = 0
    
    for i in range(1, liczba_ocen+1):
        print("Podaj ocenę " + str(i))
        ocena = float(input())
        if ocena < 0:
            break
        suma += ocena
    
    print("Suma ocen to " + str(suma))
    print("średnia ocen to " + str(suma/liczba_ocen))
    
if __name__ == "__main__":
    main()

Zwróćmy uwagę, że takie podejście ma wiele niedoróbek: choćby fakt, że dzielimy przez liczbę ocen podaną przez użytkownika na początku programu, a nie faktycznie wprowadzonych. Naprawę tego niedociągnięcia pozostawiamy Tobie, drogi Czytelniku ;).

Zadanie 2

Teraz zadanie dla Was! Korzystając z wiedzy, jaką przedstawiliśmy do tej pory (zmienne różnych typów, instrukcje warunkowe, pętle) napiszcie program, który będzie prostym kalkulatorem! Kolejne argumenty działań oraz konkretną operację do wykonania na nich będziemy podawać z klawiatury w terminalu.

Podaj w oddzielnych wierszach liczbę, operację matematyczną: +,-,*,/,%, a następnie kolejną liczbę:
12
+
3
Twój wynik to: 15
Chcesz wykonać kolejne działanie? Wpisz literę t lub n.

Gotowe rozwiązanie zadania 2 znajdziecie tutaj.


Maciej Bartoszuk

Ukończył z wyróżnieniem informatykę na wydziale Matematyki i Nauk Informacyjnych Politechniki Warszawskiej, gdzie aktualnie pracuje w zakładzie Sztucznej Inteligencji i Metod Obliczeniowych. Tam też od 2013 roku prowadzi zajęcia dydaktyczne z programowania w R, Pythonie, C/C++, C#. Uczestnik studiów doktoranckich w Instytucie Podstaw Informatyki Polskiej Akademii Nauk w latach 2013-2015. W 2018 roku obronił doktorat z wyróżnieniem na swoim rodzimym wydziale: System do oceny podobieństwa kodów źródłowych w językach funkcyjnych oparty na metodach uczenia maszynowego i agregacji danych, który obejmuje zarówno algorytmy przetwarzania kodów źródłowych programów, jak i data science. Współautor książki Przetwarzanie i analiza danych w języku Python wydanej przez PWN. Ponadto trener na bootcampach Data Science, gdzie uczy programować w języku Python pod kątem analizy danych.
Komentarze
Ostatnie posty
Data Science News #204
Data Science News #203
Data Science News #202
Data Science News #201