Cvičenie 2 - Úvod do programovacieho jazyka Python I

Cieľom druhého cvičenia je naučiť sa programovať jednoduché skripty v jazyku Python.

Súčasná verzia jazyka Python 3 zaviedla niektoré rozšírenia a zmeny, ktoré nie sú úplne kompatibilné s predchádzajúcimi verziami 2.X. Návody na cvičenia sa snažia dodržiavať spätnú kompatibilitu s verziou >2.6.

Ak už viete programovať v jazyku Python, prečítajte si aspoň odporúčania pre formátovanie kódu v kapitole o Príkazoch. Uprednostňujte rozšírenia verzie 3, ale nepoužívajte konštrukcie, ktoré nie sú kompatibilné s verziou >2.6.

Interpreter

Python je interpretovaný jazyk, ktorého interpreter spustíte príkazom python. V príkazovom riadku interpretera môžete zadávať príkazy, ktoré sa ihneď vyhodnotia (tzn. zdrojový kód nie je potrebné preložiť do spustiteľného programu). Interpreter môžete ukončiť príkazom exit(), alebo stlačením kombinácie kláves Ctrl+d. Komentáre v Pythone začínajú znakom # a pokračujú do konca riadka.

Skripty

Namiesto interaktívneho editovania príkazov v príkazovom riadku interpretera môžete príkazy zapísať do súboru. Zdrojový kód v Pythone by mal mať príponu .py. Program potom spustíte príkazom python [názov súboru].

Pre vlastné skripty si na serveri vytvorte v adresári /home/student/ adresár s vaším priezviskom a všetky svoje súbory ukladajte tam.

V prostredí Linux môžete zdrojový kód priamo skonvertovať na spustiteľný súbor. Ako prvý riadok súboru musíte uviesť komentár podľa ktorého Linux rozozná, ktorý program má použiť na interpretovanie kódu:

#!/usr/bin/python

Súbor musíte ďalej označiť ako spustiteľný. Napr. ak sa váš súbor volá skript, zadajte:

chmod +x skript

Program potom môžete spustiť priamo zadaním:

./skript

(./ je potrebné zadať ak je súbor programu uložený v aktuálnom pracovnom adresári, ktorý sa nenachádza v premennej PATH).

Nastavenie editora

Nastavenie editora je spoločné pre dvojicu na jednom serveri.

Ak budete pre editovanie kódu používať editor nano, prepnite sa do svojho domovského adresára a do vášho konfiguračného súboru editora zadajte nasledujúce nastavenia:

cd
nano .nanorc
...
include /usr/share/nano/python.nanorc
set tabsize 4
set tabstospaces

Po uložení a otvorení nového súboru v editore by ste mali mať nastavené grafické zvýrazňovanie kódu a automatické konvertovanie tabulátorov na 4 medzery.

Dátové typy a premenné

Premenné môžete definovať zápisom [meno premennej] = [hodnota]. Python neohraničuje typy premenných, tzn. do jednej premennej môžete zapísať napr. číslo a neskôr reťazec alebo iný objekt. Ak sa pokúsite pristupovať k premennej ktorá nie je definovaná, interpreter skončí chybou NameError: name 'názov premennej' is not defined.. Ak chcete definovať premennú s prázdnou hodnotou, môžete ako hodnotu zadať konštantu None.

Python rozlišuje ako základné typy Boolovské hodnoty, čísla (celé a desatinné) a reťazce.

Boolovské hodnoty

Čísla

Reťazce

Reťazce môžete zadávať do jednoduchých apostrofov alebo úvodzoviek. V interpreteri sa reťazce zobrazia tak ako ich zapíšete aj s úvodnými apostrofmi, na výpis hodnôt preto používajte príkaz print.

Samotné reťazce sú objekty, ktoré majú definované rôzne metódy slúžiace na transformáciu znakov, vyhľadávanie podreťazcov, rozdeľovanie a pod. Všetky metódy vracajú nový reťazec a pôvodný reťazec zostane nezmenený. Nasledujúca tabuľka uvádza prehľad niektorých metód.

PríkazPopis
s.lower() Prevedie všetky písmená reťazca na malé.
s.upper() Prevedie všetky písmená reťazca na veľké.
s.strip() Odstráni zo začiatku a konca reťazca prázdne znaky (medzery, tabulátory a znaky konca riadka).
s.find(sub) Vráti index prvého výskytu podreťazca sub, alebo -1 ak sa sub v reťazci nevyskytuje. Voliteľne môžete zadať počiatočný index od ktorého sa začne reťazec prehľadávať s.find(sub, start), alebo rozsah indexov v ktorom sa musí nachádzať celý podreťazec s.find(sub, start, end).
s.replace(old, new) Nahradí v reťazci všetky výskyty reťazca old za new.
s.startswith(preffix) Vráti True ak reťazec začína zadaným prefixom, inak vráti False.
s.endswith(suffix) Vráti True ak reťazec končí zadaným sufixom, inak vráti False.
s.split(sep) Rozdelí reťazec podľa zadaného oddeľovača sep a vráti zoznam rozdelených podreťazcov (pozri ďalšiu kapitolu o zoznamoch). Ak sa parameter sep vynechá, s.split() rozdelí reťazec podľa prázdnych znakov.
s.join(args) Prevedie prvky zoznamu alebo n-tice args na reťazec a spojí ich oddeľovačom s (pozri ďalšiu kapitolu o zoznamoch).
s.format(arg0, arg1, arg2, ...) Prevedie hodnoty argumentov na reťazce a nahradí nimi v reťazci s formátovacie polia ohraničené {}. Viac informácií o formátovaní nájdete v nasledujúcom príklade, alebo tu (v angličtine).

Podrobnejší popis ďalších metód nájdete tu (v angličtine).

Dátové štruktúry a objekty

Okrem základných dátových typov Python štandardne poskytuje typy pre kolekcie objektov, ako napr. zoznamy, množiny a mapy a dátové objekty pre reprezentáciu dátumov.

Zoznamy

Zoznamy sú definované ako postupnosť hodnôt ku ktorým je možné pristupovať cez index (indexovanie je od 0). V Pythone môžu zoznamy obsahovať hodnoty rôznych typov. Na rozdiel od reťazcov, prvky zoznamov je možné meniť.

Podrobnejší popis metód a viac o zoznamoch si môžete prečítať tu (v angličtine).

N-tice

N-tice (v angličtine tuples) sa používajú na zoskupenie viacerých hodnôt do jedného nemenného objektu. K prvkom n-tíc sa pristupuje podobne ako pri reťazcoch a zoznamoch indexovaním.

Množiny

Množiny sú neusporiadané kolekcie v ktorých sa každý prvok môže vyskytovať iba raz. Používajú sa napr. na odstránenie duplicitných hodnôt zo zoznamov. Vytvárajú sa napr. funkciou set([zoznam]).

Viac o množinách si môžete prečítať tu (v angličtine).

Mapy/slovníky

Mapy (v Pythone označované ako slovníky, anglicky dictionary) sú neusporiadané kolekcie dvojíc [kľúč : hodnota], pričom každý kľúč sa môže vyskytovať v kolekcii iba raz. Ako kľúč môžete použiť dátové hodnoty (čísla, reťazce a Boolovské hodnoty) a nemenné objekty (napr. n-tice zložené z dátových hodnôt a nemenných objektov).

Čas a dátumy

Okrem dátových hodnôt a kolekcií poskytuje Python aj ďalšie objekty pre reprezentáciu rôznych typov dát. Užitočné sú napr. typy pre reprezentáciu času a dátumu. Tieto typy nie sú priamo zabudované do jazyka Python, ale sú súčasťou samostatného modulu s názvom datetime. Ak ich chcete vo svojom programe využívať, musíte ich naimportovať príkazom from [názov modulu] import [názov typu].

Viac informácií o module datetime nájdete tu (v angličtine).

Príkazy

Odsadzovanie kódu medzerami alebo tabulátorom na začiatku riadku je v Pythone veľmi dôležité, pretože definuje ako sú príkazy do seba vnorené a spojené do blokov. Napr. nasledujúci kód skončí chybou IndentationError: expected an indented block:

Interpreter očakáva za podmienkou príkazu if aspoň jeden ďalší príkaz, ktorý sa vykoná ak je podmienka splnená. Keďže príkaz print 'negative value' nie je na začiatku riadku odsadený žiadnou medzerou alebo tabulátorom, Interpreter ho považuje za príkaz, ktorý by mal nasledovať za if, a príkaz if bude považovať za neukončený. Podobne, nasledujúci kód je chybný keďže sa správa negative number, reset to 0 vypíše aj pre nezáporné čísla. Aby bol príkaz print vykonaný iba pri splnení podmienky, musí byť odsadený do rovnakého bloku ako number = 0.

Pri editovaní príkazov na viacerých riadkoch, interpreter zmení výzvu z >>> na ..., tzn. správne odsadenie z predchádzajúceho príkazu bude na obrazovke vyzerať nasledovne:

>>> number = 42
>>> if number < 0:
...     number = 0
...     print 'negative, reset to 0'
...

Aby ste ukončili viacriadkový príkaz, ukončite klávesou Enter prázdny riadok. Interpreter vykoná viacriadkový príkaz a zmení výzvu na >>> pre pokračovanie ďalším príkazom.

V kóde nemiešajte odsadzovanie znakom tabulátora a medzerami!

Ak nebudete dodržiavať odsadzovanie, interpreter vypíše chybu a program nebude spustený. Aby ste zlepšili čitateľnosť vášho kódu, je dobré dodržiavať nasledujúce konvencie:

  • Namiesto tabulátora používajte základné odsadenie 4 medzerami (pri nastavenej konfigurácii bude editor nano konvertovať tabulátory automaticky).
  • Rozhodnite sa ako budete ohraničovať reťazce a dodržiavajte jeden spôsob v celom kóde (ohraničenia môžete vymeniť ak reťazec obsahuje ' alebo " aby ste nemuseli používať \' alebo \").
  • Premenné a funkcie označujte názvami s malými písmenami. Viacslovné názvy oddeľujte _ (napr. process_data).
  • Premenné, ktoré budú slúžiť v programe ako konštanty a ktoré sa nebudú pri spustení meniť pomenujte veľkými písmenami oddelenými _ (napr. DEFAULT_VALUE).
  • Vždy oddeľte operátory =, +=, -=, ==, !=, <, >, <=, >=, is, in a Boolovské spojky or, and a not medzerami (napr. x < 10 namiesto x<10).
  • Vyhnite sa vkladaniu medzier hneď za/pred [/], (/), alebo {/} (napr. x[10] namiesto x[ 10 ], f(x) namiesto f( x ), {'x': 'y'} namiesto { 'x' : 'y' }).

Ďalšie odporúčania nájdete tu (v angličtine).

Vetvenia

Cykly

Ošetrenie chýb

Ak pri vykonávaní príkazu dôjde k nejakej chybe, štandardne interpreter ukončí celý program chybovým výpisom a ďalšie príkazy sa už nevykonajú. Chyby môžete ošetriť príkazom try/except, ktorý funguje nasledovne:

  1. Najprv sa vykoná blok príkazov medzi slovami try a except.
  2. Ak nedôjde k žiadnej chybe, časť except sa preskočí a program pokračuje ďalšími príkazmi, ktoré nasledujú za try/except.
  3. Ak dôjde k chybe, typ chyby sa porovná s typom uvedeným za slovom except a ak sa zhoduje, chyba sa ošetrí príkazmi v bloku except, program potom pokračuje ďalšími príkazmi za príkazom try/except.
  4. Ak sa nenájde žiadna časť except, ktorá by pokrývala daný typ chyby, chyba zostane neošetrená a interpreter skončí program chybovým výpisom.

Príkaz try/except môže mať viacero častí except pre rôzne typy chýb. Príkazy try/except môžu byť do seba vnorené a ak sa pri chybe nenájde ošetrenie pre daný typ chyby vo vnorenom try/except, Interpreter sa pokúsi chybu ošetriť v nadradenom príkaze a až potom ukončí program ak chyba nie je pokrytá žiadnou klauzulou except.

Okrem except môžete definovať časť finally ktorá sa vykoná vždy nezávisle od toho či došlo k nejakej chybe a či bola ošetrená alebo nie (chyba musí byť ošetrená niektorým blokom except, inak program skončí po vykonaní bloku finally). Pri ošetrení chyby sa časť finally vykoná za príkazmi except.

Úlohy

Úloha 2.1

Funkcia raw_input() načíta vstup z klávesnice ukončený klávesou Enter. Naprogramujte skript jednoduchej kalkulačky, ktorá v cykle načíta na vstupe výraz:
[číslo1] [operácia] [číslo2] a vypočíta jeho hodnotu.

  1. Čísla môžu byť celé alebo desatinné a operácia môže byť +-*/.
  2. Výsledok vypíšte na 4 desatinné miesta.
  3. Skript sa ukončí ak je zadaný prázdny riadok.
  4. Pre ošetrenie chýb použite príkaz try/except.

Úloha 2.2

Na vstupe máte nasledujúce textové dáta:

data = """'power'; 'weight'; 'hybrid'; 'producer'
55.3; 1450; false; 'ford'
100; 2500; false; 'ford'
60.5; 1150; true; 'toyota'
56; ?; false; 'volkswagen'
75.2; 1480; false; 'volkswagen'
80.1; 1630; false; 'peugeot'"""

Napíšte skript, ktorý:

  1. Rozdelí text na riadky a oddelí dátové polia. Hodnoty polí prevedie z reťazca na dátový typ Pythonu, tzn. čísla, reťazce bez oddeľovačov a Boolovské hodnoty.
  2. Chýbajúce hodnoty označené ? reprezentujte konštantou None.
  3. Pre číselné polia vypíše základné štatistiky: min./max./priemernú hodnotu a štandardnú odchýlku zaokrúhlené na 4 desatinné miesta.
  4. Pre textové polia vypíše zoznam hodnôt usporiadaný podľa abecedy.

Úloha 2.3

Na vstupe máte zadaný nasledujúci text:

text = """Bridgekeeper: Hee hee heh. Stop. What... is your name?
King Arthur: It is 'Arthur', King of the Britons.
Bridgekeeper: What... is your quest?
King Arthur: To seek the Holy Grail.
Bridgekeeper: What... is the air-speed velocity of an unladen swallow?
King Arthur: What do you mean? An African or European swallow?"""

Napíšte skript, ktorý:

  1. Rozdelí text na riadky a slová. Slová prevedie na malé písmená a odstráni z textu diakritiku (' ... ?).
  2. Vypíše zoznam slov usporiadaný podľa abecedy s frekvenciami, koľkokrát slovo povedal kráľ Arthur, koľkokrát strážca mostu a aká bola frekvencia celkovo, napr.:
african   1  0  1
air-speed 1  0  0
an        1  1  2
arthur    1  0  1
...