Skip to content

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 whileu a nový, zložitejší, dátový typ.

Načítanie vstupu

Pripomeňme si náš program na kreslenie trojuholníkov:

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:

>>> 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:

>>> year = input( 'Favorite year? ' )
Favorite year? 1965
>>> year
'1965'

Vylepšenie kresliča

Načítanie veľkosti cez input() je jednoduché...

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:

>>> a = input()
1
>>> type( a )
<class 'str'>

Naozaj, výsledkom input()u je text. My potrebujeme tento text konvertovať na číslo, na pomoc nám príde ďalší príkaz -- int():

>>> int( '32' )
32
>>> int( '-1' )
-1
>>> int( 42 )
42
>>> int( '4.2' )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '4.2'
>>> int( 'd4' )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
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:

>>> int( float( '4.2' ) )
4
Ú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á:

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!

Ú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:

What's Your name? Kubko
Hello Kubko!
Ú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):

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:

if False:
    print( 'A' )
print( 'B' )
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ť):

if False:
print( 'A' )
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ť.

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.

Ú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ý:

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:

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 ife.

A zároveň

if a and b:
    ...
a b Výsledok
True True True
True False False
False True False
False False False

Alebo

if a or b:
    ...
a b Výsledok
True True True
True False True
False True True
False False False

Zápor

if not a:
    ...
a Výsledok
True False
False True

Použitie

Niekoľko prípadov použitia si ukážeme v shelli:

>>> ( 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).

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:

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.

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.

    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.

    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.

while size > 0:
    print( '*' * size )
    size -= 1

Tu sa nič nezmenilo, tak ako aj doteraz, vykreslíme trojuholník.

Úloha

Vytvorte program, ktorý nechá používateľa hádať, aké číslo si myslí počítač. Vyzerať by to mohlo podobne ako:

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.

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.

>>> [ 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' ] )
<class 'list'>

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.

>>> 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 "<stdin>", line 1, in <module>
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ť:

>>> l[1] = 2
>>> l
[1, 2, 3, 'ABCD', 5, [4.2, []]]

A prípadne celý zoznam vieme predĺžiť. Existuje viacero spôsobov:

>>> 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ť:

>>> 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ť:

>>> 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 "<stdin>", line 1, in <module>
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 "<stdin>", line 1, in <module>
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".

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.

1
2
3
4
5
6
7
8
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čí.

Úloha

Vytvorte podobný program s nasledujúcimi dvomi rozdielmi:

  1. Namiesto priemeru, vypočítajte medián:

    "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ľ:
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.

>>> 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:

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:

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.

Poznámka

Aj na textový reťazec sa môžme pozerať ako na zoznam, a to zoznam znakov.

>>> for c in 'word':
...     print( 2 * c )
...
ww
oo
rr
dd
Ú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.:

Enter one word: apple
1. letter: a
2. letter: p
3. letter: p
4. letter: l
5. letter: e