diff --git a/docs/02.md b/docs/02.md new file mode 100644 index 0000000..9e18a17 --- /dev/null +++ b/docs/02.md @@ -0,0 +1,724 @@ +# Python: vstup, riadiace štruktúry, zoznam + +Dnes si ukážeme ako v programe aj čítať, nielen vypisovať na obrazovku, ukážeme +si viac príkazov podobných `while`u a nový, zložitejší, dátový typ. + +## Načítanie vstupu + +Pripomeňme si náš program na kreslenie trojuholníkov: + +```python +size = 3 + +while size > 0: + print( '*' * size ) + size -= 1 +``` + +Na to, aby sme zmenili veľkosť, vždy znovu a znovu musíme prepísať náš zdrojový +kód. Bolo by pekné, keď by sme mali len jeden program, ten spustíme a spýta sa +nás na veľkosť, akú má použiť. Tomu sa hovorí *načítanie vstupu* a slúži na to +príkaz `input`. Poďme si ho vyskúšať v príkazovom riadku: + +```python +>>> input() +hello +'hello' +>>> input( 'Enter Your name: ' ) +Enter Your name: robot +'robot' +``` + +Po zadaní príkazu `input()`, shell čaká, pokým zadáme nejaký text a stlačíme +++enter++. Potom vypíše výsledok (rovnako ako keď sme využívali Python na rátanie +príkladov) -- výsledkom príkazu `input()` je v tomto prípade text 'hello'. Keď +medzi zátvorky vpíšeme text, použije tento text ako prompt. Vypíše ho a znovu +čaká na nás, aby sme mu niečo napísali. Výsledok `input()`u si môžme uložiť do +premennej: + +```python +>>> year = input( 'Favorite year? ' ) +Favorite year? 1965 +>>> year +'1965' +``` + +### Vylepšenie kresliča + +Načítanie veľkosti cez `input()` je jednoduché... + +```python +size = input( 'Enter size: ' ) + +while size > 0: + print( '*' * size ) + size -= 1 +``` + +...alebo nie? Dokážete zistiť z chybovej hlášky, čo sa stalo? Pri porovnávaní +`size > 0` sa Pythonu nepáči, že porovnávame 'str' a 'int', teda text a číslo. +Takže premenná "size" má typ 'str'. Pozrime sa na to v shelli: + +```python +>>> a = input() +1 +>>> type( a ) + +``` + +Naozaj, výsledkom `input()`u je text. My potrebujeme tento text konvertovať na +číslo, na pomoc nám príde ďalší príkaz -- `int()`: + +```python +>>> int( '32' ) +32 +>>> int( '-1' ) +-1 +>>> int( 42 ) +42 +>>> int( '4.2' ) +Traceback (most recent call last): + File "", line 1, in +ValueError: invalid literal for int() with base 10: '4.2' +>>> int( 'd4' ) +Traceback (most recent call last): + File "", line 1, in +ValueError: invalid literal for int() with base 10: 'd4' +>>> int( 4.2 ) +4 +>>> int( False ) +0 +``` + +Tento príkaz sa snaží hociakú hodnotu previesť na celé číslo. Keď sa to nedá, +skončí s chybou. Desatinné číslo 4.2 prevedie tak, že desatinnú časť jednoducho +zahodí. Ale text `4.2` nevie konvertovať. Na to by sme najprv museli previesť +text do desatinného čísla a potom do celého: + +```python +>>> int( float( '4.2' ) ) +4 +``` + +???+ question "Úloha" + Pre každý datový typ, ktorý poznáme, existuje takáto konvertovacia funkcia: + `int`, `float`, `str`, `bool`. Vyskúšajte si napr. konvertovať číslo na 'bool' + alebo previesť číslo na text a potom zase späť na číslo. + +Náš opravený program teda vyzerá: + +```python +size = int( input( 'Enter size: ' ) ) + +while size > 0: + print( '*' * size ) + size -= 1 +``` + +Výsledok z `input()`, čo je text, vhodíme do príkazu `int()`, a dostaneme +výsledok ako celé číslo, ktoré už môžme použiť na porovnanie, odčítanie aj +násobenie. Problém je, ak zadáme text, ktorý sa nedá konvertovať na číslo. +Tento problém sa dá vyriešiť, my to zatiaľ nevieme, ale nie je to také dôležité. +Ak chce niekto používať náš program, tak má vedieť, ako písať čísla! + +???+ question "Úloha 1" + Napíšte program, ktorý sa spýta používateľa na meno a následne ho pozdraví. Beh + programu potom môže vyzerať napríklad takto: + + ```text + What's Your name? Kubko + Hello Kubko! + ``` + +???+ question "Úloha 2" + Vytvorte program, ktorý si vyžiada rok narodenia a vypíše, koľkaté narodeniny + má daný človek v súčasnom roku. + +## Podmienený príkaz + +Jeden problém s našim kresličom trojuholníkov ale predsa len vyriešime. Keď si +teraz niekto pustí náš program a zadá veľkosť "-3", program nič nevypíše, len +ticho skončí (overte si to). Bolo by pekné používateľa informovať o tom, že +musí zadať nezápornú veľkosť. Potrebujeme otestovať, či platí `size < 0`, na to +využijeme podmienený príkaz `if`. Pozrime sa na nasledujúci program (spustite +si ho): + +```python +if 1 < 2: + print( '1 < 2' ) + +if 2 < 1: + print( 'Python is wrong' ) +else: + print( 'Python is right' ) +``` + +Anglické slovíčko "if" znamená "ak" a "else" znamená "inak". Takže, keď si +prečítame zdrojový kód, hneď vieme, ako tento nový príkaz (presnejšie, +*riadiaca štruktúra*) funguje. Ak 1 je menej než 2, napíš "1 < 2". Ak 2 < 1, +napíš "Python is wrong", inak napíš "Python is right". Všimnime si, že na konci +riadku s `if` alebo `else` je vždy dvojbodka. Rovnako sme ju tam písali, keď +sme používali `while`. Označuje, že niekoľko ďalších riadkov bude odsadených o +štyri medzeri vpravo a majú sa brať ako jeden *blok* kódu. Všimnime si rozdiel +v týchto dvoch programoch: + +```python +if False: + print( 'A' ) +print( 'B' ) +``` + +```python +if False: + print( 'A' ) + print( 'B' ) +``` + +Keď ich spustíme, každý vykoná niečo iné. Python je veľmi háklivý na medzery na +začiatku riadku. V podstate je jedno, koľko ich tam bude, ale vždy, ak má byť +nejaký blok kódu odsadený vpravo (teda vždy za dvojbodkou), nejaká medzera tam +musí byť a treba tento počet dodržiavať. Obydva nasledujúce programy skončia s +chybou (skúste si ich spustiť): + +```python +if False: +print( 'A' ) +``` + +```python +if False: + print( 'A' ) + print( 'A' ) +``` + +Prvý z nich nemá blok odsadený vôbec, druhý nepoužíva počet medzier +konzistentne. Je bežné odsadzovať bloky vždy o 4 medzery, a tak to budeme robiť +aj my. + +### elif + +K príkazom `if`, `else`, ešte existuje tretí kamarát: `elif`. Znamená niečo ako +"inak, ak ...". Ukážeme si jeho použitie, z ktorého to bude najlepšie vidieť. + +```python +grade = input() + +if grade == 'A': + print( 'Excellent!' ) +elif grade == 'B': + print( 'Good' ) +elif grade == 'C': + print( 'Not bad' ) +elif grade == 'D': + print( 'You could do better' ) +else: + print( 'I know only four grades: A, B, C, D' ) +``` + +Python najprv otestuje, či používateľ zadal písmeno "A", ak nie, otestuje "B", +atď., ak nie ani "D", vykoná posledný blok kódu. + +???+ question "Úloha" + Skúste ešte vylepšiť kresliča tak, že ak užívateľ zadá záporné číslo, napíše + mu, že musí zadať kladné (alebo nulu). Ak zadá väčšie číslo než 10, vypíše + správu otom, že je to príliš veľa a mal by požiadať o menšiu veľkosť. Ak ani + jeden z týchto scenárov sa nestane, tak potom program vykreslí trojuholník. + + Použite na to príkazy `if`, `elif` a `else`. Malá rada: odsadený môže (dokonca + musí) byť aj už odsadený kód. Napríklad nasledujúci zdrojový kód je validný: + + ```python + if 1 == 1: + if 2 == 2: + print( '1 == 1 and 2 == 2' ) + ``` + +### Logické operátory + +Už poznáme logické hodnoty: `False` a `True`. Vieme, že výsledkom porovnávacích +operátorov sú práve tieto hodnoty. Ale čo ak potrebujeme otestovať dve +podmienky naraz? Napr. "Ak vonku prší a je pondelok, nepôjdem do školy". Môžeme +taký program napísať pomocou dvoch príkazov `if`: + +```python +if wheather == 'raining': + if weekday == 'monday': + go_to_school = False +``` + +Teraz si ukážeme 3 logické operátory, ktoré nám pomôžu napísať aj zložitejšie +podmienky v jednom `if`e. + +#### A zároveň + +```python +if a and b: + ... +``` + +a | b | Výsledok +:----:|:-----:|:--------: +True | True | True +True | False | False +False | True | False +False | False | False + +#### Alebo + +```python +if a or b: + ... +``` + +a | b | Výsledok +:----:|:-----:|:--------: +True | True | True +True | False | True +False | True | True +False | False | False + +#### Zápor + +```python +if not a: + ... +``` + +a | Výsledok +:----:|:--------: +True | False +False | True + +#### Použitie + +Niekoľko prípadov použitia si ukážeme v shelli: + +```python +>>> ( 1 < 2 ) and ( 3 < 4 ) +True +>>> 'A' == 'B' or 1 != 2 +True +>>> 1 == 2 or 2 == 1 +False +>>> not 4 > 5 +True +>>> False or not 1 >= 1 +False +``` + +Zátvorky použiť môžeme, ale keďže porovnávacie operátory majú vyššiu prioritu +ako logické, vyhodnotia sa ešte pred nimi, a teda to nie je nutné. + +### Neodbytnejší kreslič + +Upravíme teraz kresliča trojuholníkov tak, aby v prípade nevalidnej veľkosti +neskončil hneď, ale bol neodbytný a pýtal sa na veľkosť, pokým nejakú nedostane +(alebo nebude nakoniec v zúrivosti vypnutý pomocou ++ctrl+c++). + +```python linenums="1" +done = False + +while not done: + size = int( input( 'Enter size: ' ) ) + + if size < 0 or size > 10: + print( 'Error!' ) + + if size < 0: + print( 'We need a non-negative size' ) + elif size > 10: + print( 'This is too much. We accept at most size of 10.' ) + else: + done = True + +while size > 0: + print( '*' * size ) + size -= 1 +``` + +Prejdime si zdrojový kód riadok za riadkom: + +```python linenums="1" +done = False +``` + +V tejto premennej si budeme uchovávať informáciu o tom, či sa nám už podarilo +načítať validný vstup (veľkosť). Na začiatku programu rozhodne ešte žiaden +vstup od užívateľa nemáme, preto nastavíme `done` na `False`. + +```python linenums="3" +while not done: + size = int( input( 'Enter size: ' ) ) +``` + +Toto je hlavný cyklus načítavania veľkosti. Pokým nebudeme mať poznačené v +`done`, že už sme načítali dobrý vstup, cyklus sa bude opakovať. Spôsob +načítania už poznáme. + +```python linenums="6" + if size < 0 or size > 10: + print( 'Error!' ) + + if size < 0: + print( 'We need a non-negative size' ) + elif size > 10: + print( 'This is too much. We accept at most size of 10.' ) +``` + +Otestujeme, či je veľkosť validná. Ak nie, napíšeme používateľovi, že niečo je +zle a potom aj ČO je zle. + +```python linenums="13" + else: + done = True +``` + +Ak je všetko OK, poznačíme si, že sa nám podarilo načítať veľkosť, a tak pri +ďalšom testovaní podmienky cyklu, výraz `not done` sa vyhodnotí na False a +program bude pokračovať za `while` cyklom. + +```python linenums="16" +while size > 0: + print( '*' * size ) + size -= 1 +``` + +Tu sa nič nezmenilo, tak ako aj doteraz, vykreslíme trojuholník. + +???+ question "Úloha" + Vytvorte program, ktorý nechá používateľa hádať, aké číslo si myslí počítač. + Vyzerať by to mohlo podobne ako: + + ```text + Let's play a game: Guess the number I've chosen (1..100 inclusive) + Your guess: 12 + Try a greater number + Your guess: 50 + Try a lower number + Your guess: 45 + Try a lower number + Your guess: 42 + Congratulation! + ``` + + Poznámka: Vytvoriť v programe náhodné číslo ešte nevieme, zatiaľ kľudne môže + byť toto číslo priamo napísané v zdrojovom kóde a uložené v premennej na + začiatku kódu. + + ```python + number = 42 + + # Main program logic follows... + ``` + +## Zoznam + +Zopakujme si, aké dátové typy poznáme: + +* celé čísla - 'int' +* desatinné čísla - 'float' +* textový reťazec - 'str' +* logická hodnota - 'bool' + +Teraz si do tohto zoznamu pridáme ďalší: + +* zoznam - 'list' + +Ako aj názov napovedá, do zoznamu si budeme ukladať viacero hodnôt. Je to +vlastne postupnosť čísel, textu, logických hodnôt, ..., dokonca aj samotných +zoznamov. Aby sme vytvorili zoznam hodnôt, vpíšeme ich medzi hranaté zátvorky. + +```python +>>> [ 1, 2, 3, 4, 5 ] +[1, 2, 3, 4, 5] +>>> [ 1, False, 3, 'ABCD', 5, [ 4.2, [] ] ] +[1, False, 3, 'ABCD', 5, [4.2, []]] +>>> type( [ 1, False, 'ABC' ] ) + +``` + +Hodnoty uložené v zozname nazývame *prvky* a pristupujeme k nim cez *index*. +Index je poradie prvku od začiatku zoznamu, pričom prvý prvok má index 0. Na +indexovanie používame hranaté zátvorky. + +```python +>>> l = [ 1, False, 3, 'ABCD', 5, [ 4.2, [] ] ] +>>> l[0] +1 +>>> l[1] +False +>>> l[5] +[4.2, []] +>>> l[5][1] +[] +>>> l[-1] +[4.2, []] +>>> l[-2] +5 +>>> l[6] +Traceback (most recent call last): + File "", line 1, in +IndexError: list index out of range +``` + +Indexy môžu byť aj záporné, vtedy označuje poradie odzadu. No pozor na príliš +vysoké indexy. Ak chceme pristúpiť k prvku za koncom zoznamu, dostaneme chybovú +hlášku. + +Prvky v zozname môžeme aj upravovať: + +```python +>>> l[1] = 2 +>>> l +[1, 2, 3, 'ABCD', 5, [4.2, []]] +``` + +A prípadne celý zoznam vieme predĺžiť. Existuje viacero spôsobov: + +```python +>>> l = [ 1, 2 ] +>>> l.append( 3 ) +>>> l +[1, 2, 3] +>>> l.extend( [ 4, 5, 5 ] ) +>>> l +[1, 2, 3, 4, 5, 5] +>>> l + [ 0 ] +[1, 2, 3, 4, 5, 5, 0] +>>> l +[1, 2, 3, 4, 5, 5] +>>> l += [ 0 ] +>>> l +[1, 2, 3, 4, 5, 5, 0] +``` + +Operátor `+` vytvorí **nový** zoznam z pôvodných dvoch -- tieto dva zostanú +nezmenené. Ak chceme zoznam predĺžiť, a teda naozaj ho zmeniť, musíme +na to použiť operátor `+=`. +A vieme ho zase skrátiť: + +```python +>>> l.pop() +0 +>>> l +[1, 2, 3, 4, 5, 5] +>>> a = l.pop() +>>> a +5 +>>> l +[1, 2, 3, 4, 5] +>>> del l[1] +>>> l +[1, 3, 4, 5] +``` + +`pop()` zmaže posledný prvok, ktorý si zároveň môžeme niekam uložiť. `del` +vymaže ľubovoľný prvok na danom indexe. + +Ukážme si, čo ešte vieme so zoznamom robiť: + +```python +>>> l.reverse() # obráti zoznam +>>> l +[5, 4, 3, 1] +>>> l.clear() # vymaže všetky prvky +>>> l +[] +>>> l = [ 1 ] +>>> l.insert( 0, 8 ) # vloží prvok 8 na index 0 +>>> l +[8, 1] +>>> l.insert( 1, 9 ) +>>> l +[8, 9, 1] +>>> l.remove( 8 ) # odstráni prvý výskit prvku 8 +>>> l +[9, 1] +>>> l.remove( 0 ) # ak daný prvok neexistuje, chyba +Traceback (most recent call last): + File "", line 1, in +ValueError: list.remove(x): x not in list +>>> l = [ 1, 4, 4, 9, 2, 0, 3, 4 ] +>>> l.count( 1 ) # spočíta počet výskitov prvku +1 +>>> l.count( 4 ) +3 +>>> l.count( 42 ) +0 +>>> l.sort() # zoradí zoznam +>>> l +[0, 1, 2, 3, 4, 4, 4, 9] +>>> l.index( 4 ) # vráti index prvého výskitu prvku +4 +>>> l.index( 5 ) # chyba, podobne ako pri 'remove' +Traceback (most recent call last): + File "", line 1, in +ValueError: 5 is not in list +>>> len( l ) # zistí dĺžku (počet prvkov) zoznamu +8 +>>> len( [ 'robo', 'lab' ] ) +2 +>>> len( [] ) +0 +>>> 3 in [ 2, 3, 1 ] # test na prítomnosť prvku v zozname +True +>>> 1 in [ 4, 5 ] +False +>>> 'l' in 'hello' +True +>>> 0 in [] +False +``` + +### Priemer čísel + +Aby sme si ukázali príklad využitia zoznamu, vytvoríme program, ktorý vypočíta +priemer čísel zadaných používateľom. Tie si budeme ukladať do zoznamu. Ako +budeme ale vedieť, kedy užívateľ už napísal všetky čísla? Dáme mu možnosť to +oznámiť napr. tým, že zadá text "end". + +```python linenums="1" +print( 'I\'ll compute the mean value of all the entered numbers.' ) +print( 'Type "end" after entering all of them.' ) + +done = False +numbers = [] + +while not done: + number = input( 'Enter a number (or "end"): ' ) + + if number == 'end': + done = True + else: + numbers.append( int( number ) ) + +print( 'Entered numbers:', numbers ) +``` + +Na začiatku užívateľa informujeme o tom ako používať náš program. Všimnime si, +že na to, aby sme vypísali jednoduchú úvodzovku, musíme pred ňu napísať +špeciálny znak spätné lomítko (\\). Je to preto, lebo úvodzovkami sa označuje +začiatok a koniec textového reťazca. Ak by sme nepoužili spätné lomítko, Python +by ako text pochopil iba "I" a dostali by sme chybu. + +Vstup načítame najprv ako text, aby sme mohli otestovať koniec zadávania čísel, +a keď ten nenastane, konvertujeme ho na celé číslo a pridáme do zoznamu. Na +konci vypíšeme všetky čísla z ktorých budeme rátať priemer. + +```python linenums="1" +i = 0 +summ = 0 + +while i < len( numbers ): + summ += numbers[i] + i += 1 + +print( 'Mean:', summ / len( numbers ) ) +``` + +Aby sme vypočítali priemer, najprv pomocou cyklu sčítame všetky čísla. Premenná +`i` má na začiatku hodnotu nula, teda index prvého prvu. Postupne sa zvyšuje o +jedna, takže sa posúvame na ďalšie prvky. Musíme si dať pozor, aby sme +zastavili cyklus dostatočne skoro a zároveň nezabudli na žiaden prvok. Index +prvého prvku je nula, index druhého jedna, atď. Takže ak dĺžka zoznamu je 5, +posledný index je 4. Posledný index je vždy o jedna menší než dĺžka zoznamu. +Preto sme použili v podmienke porovnanie `i < len( numbers )`. Keď po poslednom +prvku zvýšime `i` o jedna, už sa bude rovnať dĺžke zoznamu, a cyklus skončí. + +???+ question "Úloha" + Vytvorte podobný program s nasledujúcimi dvomi rozdielmi: + + 1. Namiesto priemeru, vypočítajte + [medián](https://sk.wikipedia.org/wiki/Medi%C3%A1n): + > "Na nájdenie mediánu daného súboru stačí hodnoty usporiadať podľa + > veľkosti a zobrať hodnotu, ktorá sa nachádza v strede zoznamu. Ak má + > súbor párny počet prvkov, zvyčajne sa za medián označí aritmetický + > priemer hodnôt na mieste n/2 a (n+2)/2, ktoré sa nachádzajú v oblasti + > prostrednej hodnoty." + 2. Užívateľ najprv zadá koľko čísel bude nasledovať, potom na každom riadku + napíše jedno číslo. Takže už nemusí ukončiť čísla textom "end". Príklad + toho, čo môže zadať používateľ: + + ```text + 4 + 25 + 7 + 1 + 13 + ``` + + Medián týchto štyroch čísel je (7 + 13) / 2 = 10. + +### for ... in ... + +Na *iterovanie* (prechádzanie prvkov) cez zoznam sme použili `while` cyklus. +Nie je to jediná možnosť a v tejto časti si ukážeme vhodnejšiu riadiacu +štruktúru. + +```python +>>> for n in [ 1, 5, 3 ]: +... print( 'n =', n ) +... +n = 1 +n = 5 +n = 3 +``` + +Na konci príkazu `for in` je dvojbodka, takže telo cyklu znovu musí byť +odsadené doprava. Takéto krátke programy vieme písať aj priamo v shelli, `...` +na začiatku znamenajú, že náš program/príkaz pokračuje. Za poslednými `...` +stlačíme hneď Enter, tým dáme najavo, že sme náš program dopísali a shell ho +spustí (interpretuje). + +Medzi slovíčkami `for` a `in` píšeme názov premennej. Do tejto premennej budú +postupne ukladané všetky hodnoty zo zoznamu uvedenom po `in`. + +Tento nový typ cyklu využijeme v programe rátajúcom priemer čísel. Namiesto +`while` cyklu a pomocnej premennej `i`, napíšeme len: + +```python +summ = 0 + +for number in numbers: + summ += number +``` + +- - - +Program vieme dokonca zjednodušiť ešte viac. Python pozná príkaz `sum()`, +ktorým sčíta všetky hodnoty v zozname: + +```python +summ = sum( numbers ) +``` + +Mimochodom, to je dôvod, prečo sme na názov premennej nepoužili "sum" ale +"summ". Podobne by sme nemali používať názvy premenných ako "for", "in", +"else", atď. Väčšinou platí, že ak nám editor zafarbí slovo na nejakú farbu, +tak je to slovo vyhradené pre jazyk Python a ak nechceme mať problémy, nebudeme +ho používať na názov premennej. + +!!! note "Poznámka" + Aj na textový reťazec sa môžme pozerať ako na zoznam, a to zoznam znakov. + + ```python + >>> for c in 'word': + ... print( 2 * c ) + ... + ww + oo + rr + dd + ``` + +???+ question "Úloha" + Napíšte program, ktorý sa spýta užívateľa na jedno, ľubovoľné slovo. Potom + vypíše jeho písmena spolu s poradím. Napr.: + + ```text + Enter one word: apple + 1. letter: a + 2. letter: p + 3. letter: p + 4. letter: l + 5. letter: e + ``` diff --git a/mkdocs.yml b/mkdocs.yml index 21a5cdd..636f5f2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,6 +6,7 @@ theme: nav: - Home: index.md + - 02.md markdown_extensions: - pymdownx.highlight: