Instant Hacking

Toto je stručný úvod do programování s příklady napsanými v jazyce Python. (Jestliže již umíte programovat, ale toužíte po úvodu do Pythonu, může se vám hodit můj článek Instant Python). Tento článek byl dosud přeložen do italštiny, polštiny, japonštiny, srbštiny, brazilské portugalštiny, nizozemštiny a češtiny.

Poznámka překladatele: Pokud v tomto textu naleznete nějakou chybu, nepřesnost, překlep,… prostě cokoliv, napište mi o tom, prosím, e-mail na adresu david(zavináč)kolibac(tečka)cz.

Tato stránka není o vlamování se do cizích počítačů apod. Nezajímá mne to, takže mi o tom, prosím, nepište.

Poznámka: Aby vše fungovalo, jak má, pište programy do textového souboru a až poté je spouštějte v interpretru; nesnažte se je psát přímo do interpretru — ne všechny pak budou fungovat. (Neptejte se mne, prosím, na detaily. Podívejte se do dokumentace nebo napište e-mail na help@python.org.)

Poznámka překladatele: Lidem neovládajícím angličtinu se může hodit česká konference o Pythonu a vůbec celý web České komunity programátorů a uživatelů jazyka Python.

Prostředí

Pro programování v Pythonu musíte mít nainstalovaný interpreter Pythonu. Ten existuje pro většinu platforem (včetně Macintoshe, Unixu a Windows). Více informací naleznete na webu Pythonu. Také byste měli mít textový editor (třeba Emacs, Notepad nebo něco podobného).

Poznámka překladatele: Ačkoliv je v době překladu tohoto textu již dostupný Python 3.2, který je i ze syntaktického hlediska zpětně nekompatibilní s dřívějšími verzemi, zde bude nadále používán Python verze 2.x (obvykle 2.6 nebo 2.7), jelikož se zatím nachází na většině systémů a existuje pro něj větší množství knihoven než pro novou verzi.

Co je to programování?

Když programujete počítač znamená to, že mu dáváte příkazy, co má dělat. Počítačové programy v mnoha věcech připomínají recepty, podle nichž třeba vaříme. Například [1]:

Slavnostní šunkový salát (pro 4 osoby)



Přísady:



Marináda:

    1/4 šálku citronové šťávy

    1/4 šálku nepříliš slané sójové omáčky

    1/4 šálku vody

    1 kávová lžička rostlinného oleje

    3/4 kávové lžičky šalvěje

    1/2 kávové lžičky oregana

    1/4 kávové lžičky chilli omáčky

    2 stroužky rozetřeného česneku



Salát:

    1 dvanáctiuncová konzerva nepříliš slaného lančmítu (mleté kořeněné maso) nakrájeného na proužky

    1 nakrájená cibule

    1 na proužky nakrájená paprika

    salát

    12 rozpůlených keříčkových rajčat



Postup:



V nádobě s přesně sedící pokličkou smíchejte a řádně protřepejte ingredience na marinádu.

Umístěte proužky šunky do igelitového pytlíku a polijte je marinádou. Pytlík uzavřete;

marinujte jej 30 minut v ledničce. Vyjměte šunku z pytlíku; odejměte 2 kávové lžičky marinády.

Ohřejte odejmutou marinádu na velké pánvi. Přidejte šunku, cibuli a papriku. Smažte 3 až 4 minuty,

nebo dokud není šunka hotová. Vložte do 4 salátových misek listy salátu a zalijte je horkou

salátovou směsí. Ozdobte rozpůlenými rajčaty. Podávejte.

Tomuto žádný počítač rozumět nebude… A valná většina počítačů není schopna vyrobit šunkový salát i kdyby rozuměla návodu. Co tedy musíme udělat, aby to bylo pro počítač srozumitelnější? V zásadě dvě věci. Musíme (1) hovořit k počítači jazykem, kterému rozumí, a (2) musíme po něm chtít věci, které nám může splnit.

První bod znamená, že musíme použít jazyk — programovací jazyk, pro který máme interpretační program, a druhý bod znamená, že nemůžeme očekávat, že nám počítač udělá salát — ale můžeme očekávat, že bude sčítat čísla, vypisovat něco na obrazovku atd.

Ahoj…

Je tradicí, že učebnice programovacích jazyků vždy začínají programem, který vypíše na obrazovku text „Ahoj, světe!“. V Pythonu je to velmi jednoduché:

print "Ahoj, svete!"

Poznámka překladatele: Ve zdrojových kódech příkladů v tomto textu nebude používána diakritika. Při správném nastavení systému s ní samozřejmě potíže nejsou, ale ne všechny systémy jsou správně nastavené…

Ono je to v podstatě stejné jako recept uvedený výše (ačkoliv je to mnohem, mnohem kratší). Říká to počítači, co má dělat: vypsat text „Ahoj, světe!“. Co když budeme chtít, aby toho náš program dělal více?

print "Ahoj, svete!"

print "Nashledanou, svete!"

To nebylo o moc složitější, že ne? Ale také ne o moc zajímavější… Chtěli bychom udělat něco s přísadami, podobně jako v receptu na šunkový salát. Dobrá — co máme za přísady? Máme řetězce textu, jako je "Ahoj, svete!", ale máme také čísla. Dejme tomu, že chceme po počítači, aby nám spočítal obsah obdélníku. Můžeme mu tedy dát následující drobný recept:

# Obsah obdelniku



# Prisady:

sirka = 20

vyska = 30



# Postup:

obsah = sirka * vyska

print obsah

Na tomto příkladu můžete vidět (ač nepříliš patrnou) podobnost s receptem na šunkový salát. Ale jak to vlastně funguje? Za prvé, řádky začínající znakem # se nazývají komentáře a počítač je ignoruje. Ale používání takovýchto drobných vysvětlení může pomoci čitelnosti programu pro lidi.

Dále, řádkům, které vypadají jako neco = cosi, se říká přiřazení. V případě sirka = 20 říkáme počítači, že od teď by se měla šířka rovnat dvaceti. Co znamená, že „šířka je dvacet“? Znamená to, že proměnná jménem „sirka“ je vytvořena (nebo je opětovně použita, pokud již existuje) a je jí předána hodnota 20. Takže když tuto proměnnou použijeme později, počítač zná její hodnotu. Tím pádem

sirka*vyska

je v podstatě to samé jako

20*30

a to je vypočteno s výsledkem 600, což je přiřazeno proměnné obsah. Poslední příkaz v programu vypíše obsah proměnné obsah, takže to, co vidíte při spuštění programu je prostě

600

Poznámka: V některých jazycích musíte říci počítači, co budete potřebovat za proměnné, hned na začátku programu (podobně, jako je tomu u přísad do salátu) — Python je dost chytrý na to, aby si s proměnnými poradil za chodu.

Zpětná vazba

OK. Nyní umíte vytvářet jednoduché i trošku složitější výpočty. Třeba budete chtít vytvořit program, který bude počítat obsah kruhu namísto obdélníku:

polomer = 30



print polomer * polomer * 3.14

To ale není o moc zajímavější než program s obdélníkem. Nebo alespoň podle mého názoru. Je to jaksi neobratné. Co když budeme chtít znát obsah kruhu o poloměru 31? Jak to počítači sdělit? Je to trošku jako v části receptu na salát: „Smažte 3 až 4 minuty, nebo dokud není šunka hotová.“ Abychom se dozvěděli, zda je šunka hotová, musíme si to zjistit. Potřebujeme zpětnou vazbu, nebo nějaký vstup informací. A jak má počítač znát poloměr našeho kruhu? Také potřebuje vstup… Takže mu můžeme říci, aby si zjistil poloměr:

polomer = input("Jaky je polomer? ")

print polomer * polomer * 3.14

Teď to konečně začíná být zajímavé… input je cosi, čemu se říká funkce. (Za chvíli se naučíte psát vlastní funkce. input je funkce vestavěná do jazyka Python.) Prostým napsáním

input

toho moc nenaděláte. Musíte za něj přidat závorky. input() už pracovat bude — bude čekat, až uživatel zadá poloměr. Verze uvedená výše je poněkud uživatelsky přívětivější, jelikož první vytiskne otázku. Když dáme něco jako tento dotazovací řetězec do závorek volání funkce, říká se tomu předávání parametru funkci. Věc (nebo věci) v závorce je (jsou) parametr(y). V našem případě předáváme otázku jako parametr, takže input ví, co má vypsat předtím, než bude čekat na uživatelovu odpověď.

Jak ale dostat odpověď do proměnné polomer? Funkce input (podobně jako spousta jiných funkcí) po zavolání vrací hodnotu. Tuto hodnotu nemusíme použít, ale v našem případě ji použít chceme. Následující dva příkazy mají zcela odlišné významy:

neco = input



cosi = input()

neco nyní obsahuje vstupní funkci samu o sobě (takže je možné použít neco("Kolik je ti let? "); říká se tomu dynamické volání funkce), zatímco cosi obsahuje to, co napsal uživatel.

Tok

Nyní dokážeme psát programy pro vykonávání základních úkonů (aritmetických, vypisovacích) a umíme přijímat vstup od uživatele. To je užitečné, ale stále jsme omezování tzv. sekvenčním prováděním příkazů — to znamená, že musí vykonány v přesném pořadí. Valná část receptu na šunkový salát je takto sekvenční nebo lineární. Ale co kdybychom chtěli, aby nám počítač kontroloval smažení šunky? Je-li již tepelně upravená, měla by jít z pánve pryč — jinak by na ní měla ještě nějakou tu minutku zůstat. Jak to vyjádřit?

To, co chceme, je kontrola toku programu. Ten totiž může téct dvěma směry — buď šunku vyndáme z trouby, nebo ji v ní necháme. Můžeme si vybrat, podmínkou je, zda je šunka dostatečně tepelně upravená. Říká se tomu podmíněné provádění. Můžeme to udělat takto:

teplota = input("Jaka je teplota v troube?")



if teplota > 50:

    print "Salat je jiz tepelne upraven."

else:

    print "Salat potrebuje jeste chvili smazeni."

Smysl by měl být jasný: Jestliže je teplota vyšší než 50 (stupňů Celsia), vypíše se zpráva upozorňující uživatele na to, že šunka je usmažená, jinak je uživatel upozorněn, že by měl salát ještě chvíli smažit.

Poznámka: Odsazování je v Pythonu důležité. Bloky při podmíněném provedení (a v cyklech a definicích funkcí — viz níže) musí být odsazeny (a navíc musí být odsazeny stejným počtem bílých znaků; tabulátor se počítá jako osm mezer), aby interpret mohl určit, kde začínají a kde končí. Díky tomu jsou programy čitelnější i pro lidi.

Vraťme se k našemu výpočtu obsahu. Chápete, co dělá?

# Program pro vypocet obsahu



print “Vitejte v Programu pro vypocet obsahu”

print “–––––––––––––”

print



# Vypis nabidky:

print “Vyberte tvar, prosim:”

print “1  Obdelnik”

print “2  Kruh”



# Ziskani uzivatelovy volby:

tvar = input(“> “)



# Vypocet obsahu:

if tvar == 1:

    vyska = input(“Zadejte vysku, prosim: “)

    sirka = input(“Zadejte sirku, prosim: “)

    obsah = vyska*sirka

    print “Obsah je”, obsah

else:

    polomer = input(“Zadejte polomer, prosim: “)

    obsah = 3.14*(polomer**2)

    print “Obsah je”, obsah

Novinky v tomto příkladu:

  1. osamocený příkaz print způsobí vytisknutí prázdného řádku
  2. == kontroluje, jestli jsou si dvě hodnoty rovny, na rozdíl od =, kterým se přiřazuje hodnota z pravé strany do proměnné na levé straně. To je zásadní odlišnost!
  3. operátor ** slouží v Pythonu k mocnění — druhou mocninu poloměru tedy zapíšeme jako polomer**2.
  4. print může vypsat více věcí, stačí je oddělit čárkami. (Na výstupu budou odděleny mezerami.)

Program je celkem jednoduchý: Zeptá se na číslo, které určuje, zda uživatel chce spočítat obsah obdélníku, nebo kruhu. Pak je použit výraz if (podmíněné proveddní) pro rozhodnutí, který blok se má použít pro výpočet obsahu. Tyto bloky jsou v podstatě stejné jako ty použité v dřívějších příkladech. Všimněte si, jak dělají komentáře program čitelnějším. První přikázání programování zní: „Budeš používat komentáře.“ Každopádně je to docela dobrý zvyk.

Cvičení 1

Rozšiřte výše uvedený program tak, aby počítal i obsah čtverce, přičemž uživatel bude muset zadat délku jen jedné strany. Abyste mohli něco takového udělat, musíte vědět jednu věc: Jsou-li možné více než dvě volby, můžete napsat něco jako:

if neco == 1:

    # Delej neco...

elif neco == 2:

    # Delej neco jineho...

elif neco == 3:

    # Delej neco uplne jineho...

else:

    # Kdyz vsechno ostatni selze...

Zde tajemné elif znamená v podstatě „else if“ :). Takže pokud bude neco rovno jedné, pak se bude něco dělat, pokud bude neco rovno dvěma, bude se dělat něco jiného,… Můžete přidat do programů i další volby — třeba pro výpočet obsahu trojúhelníků nebo libovolných jiných mnohoúhelníků, je to na vás.

Cykly

Sekvenční a podmíněné vykonávání příkazů, to jsou jen dva ze tří základních stavebních kamenů programování. Tím třetích je cyklus. V předchozí kapitole jsme navrhli řešení zjišťování, zda je již šunka dostatečně tepelně upravená, bylo to ovšem poněkud nevhodné řešení. Co kdyby šunka nebyla hotová ani v době dalšího zjišťování jejího stavu? Můžeme vůbec vědět, kolikrát bychom to museli zjišťovat? Ve skutečnosti nemůžeme. A neměli bychom. Měli bychom být schopni dát počítači za úkol kontrolování stavu šunky, dokud by nebyla hotová. Jak to uděláme? Uhodli jste ---použijeme cyklus, neboli opakované provádění.

Python zná dva typy cyklů: cykly while a cykly for. Cykly for jsou asi snadnější. Například:

for jidlo in "sunka", "vejce", "rajcata":

    print "Miluji", jidlo

To znamená: Pro každý prvek v seznamu "sunka", "vejce", "rajcata" se má vytisknout, že jej milujete. Blok uvnitř cyklu je proveden pro každý prvek jednou, pokaždé, když je aktuální prvek přiřazen do proměnné jidlo (v tomto případě). Jiný příklad:

for cislo in range(1,100):

    print "Ahoj, svete!"

    print "Zbyva uz jen", 100 - cislo, "cisel..."



print "Ahoj, svete!"

print "To bylo posledni...  Uf!"

Funkce range vrací seznam čísel ze zadaného intervalu (včetně prvního a vyjma posledního čísla… V tomto případě [1..99]). Jinými slovy to znamená:

To nám ale opravdu nepomůže s naším problémem se smažením. Pokud bychom chtěli šunku zkontrolovat stokrát, bylo by to pěkné řešení; jenže my nevíme, zda je počet kontrol dostatečný, nebo příliš vysoký. Prostě chceme kontrolovat šunku, dokud je nedostatečně tepelně upravená (nebo dokud není dostatečně tepelně upravená — záleží na úhlu pohledu). Takže použijeme cyklus while:

# Program pro smazeni sunky



# Ziskani funkce *sleep*

from time import sleep



print "Zacni, prosim, se smazenim sunky. (Vratim se za tri minuty.)"



# Cekej 3 minuty (tzn. 3*60 sekund) „

sleep(180)



print "Jsem zpeeet :)"



# Jak teple je dostatecne teple?

dost_teple = 50



teplota = input("Jak je sunka tepla? ")

while teplota < dost_teple:

    print "Malo teple... Jeste chvili smazte...")

    sleep(30)

    teplota = input("OK. Jak je sunka tepla nyni? ")



print "Je to dost teple — hotovo!"

Novinky v tomto příkladu…

  1. Některé užitečné funkce jsou ukryty v modulech, mohou být importovány. V tomto případě importujeme funkci sleep (která spí po zadaný počet sekund) z modulu time, který je distribuován společně s Pythonem. (Můžete si vytvářet i své vlastní moduly…)

Cvičení 2

Napište program, který plynule čte čísla od uživatele a sčítá je dokud součet nedosáhne stovky. Napište jiný program, který načte 100 čísel od uživatele a vypíše jejich součet.

Větší programy — abstrakce

Když chcete získat představu o obsahu knihy, nepřečtete si všechny její stránky — jen se podíváte do obsahu, že ano? Jsou v něm stručně vypsány názvy jednotlivých kapitol. A teď si představte psaní kuchařky. Mnoho receptů, například „Krémová šunka s makaróny“ nebo „Švýcarský šunkový koláč“, může obsahovat spoustu podobných věcí, v tomto případě třeba šunku — jistě byste nechtěli v každém receptu popisovat, jak se dělá šunka. (Ve skutečnosti si sice šunku obvykle sami nevyrábíme, ale sneste tuto nepřesnost, je to přece jen příklad :)) Takže napíšete zvláštní kapitolu o výrobě šunky a v jiných receptech se na ni budete odkazovat. To znamená, že nebudete pokaždé psát celý recept se vším všudy, ale jen se odkážete na příslušnou kapitolu s podrobnostmi jejím jménem. V programování se tomu říká abstrakce.

Už jsme něco takového dělali? Ano. Namísto přesného vysvětlování počítači, jak získat od uživatele nějaký vstup (dobrá, to bychom nedokázali… asi tak jako bychom si těžko dokázali vyrobit šunku, takže… :)), jsme použili input — funkci. Funkce si můžeme dokonce sami vytvářet, je to určitá forma abstrakce.

Řekněme, že chceme najít největší celé číslo, které je menší než zadané kladné číslo. Například pro 2,7 by to bylo 2. Často se tomu říká „celá část“ daného čísla. (Mohli bychom toho dosáhnout pomocí vestavěné funkce Pythonu int, ale mějte se mnou strpení…) Jak to udělat? Mohli bychom otestovat všechny hodnoty větší než nula:

cislo = input("Zadejte cislo: ")



cela_cast = 0

while cela_cast <= cislo:

    cela_cast = cela_cast + 1

cela_cast = cela_cast - 1



print "Cela cast cisla", cislo, "je", cela_cast

Všimněte si, že cyklus končí až cela_cast již není menší (nebo rovna) číslu; přidáme k ní příliš mnoho. Musíme tedy nakonec jedničku odečíst. Co kdybychom chtěli použít tuto „celou část“ v komplexním matematickém výrazu? Museli bychom opisovat celý cyklus pro každé číslo, jehož „celou část“ bychom potřebovali. To není moc pěkné… Asi vás napadlo, co bychom mohli udělat místo toho — mohli bychom si vytvořit vlastní funkci nazvanou „celá část“:

def cela_cast(cislo):

    vysledek = 0

    while vysledek <= cislo:

        vysledek = vysledek + 1

    vysledek = vysledek - 1

    return vysledek

Novinky v tomto příkladu…

  1. Funkce jsou definovány pomocí klíčového slova def následovaného jménem funkce a požadovanými parametry uvedenými v závorkách.
  2. Pokud má funkce vracet hodnotu, je tato hodnota vrácena díky použití klíčového slova return (které také ukončuje funkci).

To, co jsme definovali, můžeme nyní použít:

x = 2.7

y = cela_cast(x)

Poté by hodnota y měla být 2. Je také možné vytvářet funkce s více parametry:

def soucet(x, y):

    return x + y

Cvičení 3

Napište funkci implementující Euklidův algoritmus pro nalezení největšího společného dělitele dvou čísel. Algoritmus funguje takto:

  1. Jsou dána dvě čísla a a b, a je větší než b.
  2. Následující se opakuje, dokud není b rovno nule:
  3. Hodnota a je změněna na hodnotu b.
  4. Hodnota b je změněna na zbytek po dělení hodnoty a (před změnou) hodnotou b (před změnou).
  5. Poslední hodnota a je největším společným dělitelem čísel.

Rady:

  1. Použijte a a b jako parametry funkce.
  2. Pro jednoduchost předpokládejte, že a je větší než b.
  3. Zbytek po dělení čísla x číslem z se zapíše jako x % z.
  4. Hodnoty mohou být přiřazeny do dvou proměnných současně: x, y = y, y + 1. V tomto případě je do x uložena hodnota y (tzn. hodnota y před přiřazením) a hodnota y je zvýšena o jedničku.

Více o funkcích

Jak vám šlo řešení úkolu? Bylo to složité? Stále jste zmateni, co se funkcí týče? Nedělejte si starosti — toto téma ještě neopouštíme.

Druh abstrakce, který jsme použili při vytváření funkcí, se nazývá procedurální abstrakce; v mnoha programovacích jazycích se používá slovo procedura i slovo funkce. Tyto dva koncepty se ve skutečnosti liší, nicméně v Pythonu jsou obě nazývány funkcemi (ostatně se víceméně stejně definují i používají).

Jaký je (v jiných programovacích jazycích) rozdíl mezi funkcemi a procedurami? Jak jste si mohli všimnout v minulé kapitole, funkce vrací hodnotu. Rozdíl tedy spočívá v tom, že procedury žádnou hodnotu nevrací. Často se dělení funkcí na dva typy — na ty, které hodnotu vrací a na ty, které hodnotu nevrací — může hodit.

Funkce, která nevrací hodnotu („procedura“), se používá jako podprogram. Zavoláme funkci a program něco dělá, třeba vyrábí šlehačku. Takovou funkci můžeme použít na více místech, abychom nemuseli znovu psát kód. (Říká se tomu znovupoužití kódu — více na toto téma později.)

Užitečnost takové funkce (nebo procedury) spočívá ve vedlejším efektu — mění se prostředí, v němž funkce běží (například smícháním cukru a smetany a následným šleháním). Podívejme se na příklad:

def ahoj(kdo):

    print "Ahoj,", kdo



ahoj("svete")

# vypise "Ahoj, svete"

Vypisování se zde říká vedlejší efekt a jelikož je to to jediné, co funkce dělá, je tato funkce typickou procedurou. Ale… ve skutečnosti tato funkce nemění prostředí, v němž běží, že ne? Jak by to mohla udělat? Vyzkoušejme:

# *spatny* zpusob, jak to udelat

vek = 0



def nastavVek(v):

    vek = v



nastavVek(100)

print vek

# vypise "0"

Copak je tady špatně? Problém je, že funkce nastavVek si vytváří svou vlastní lokální proměnnou, která se také jmenuje vek, ale existuje pouze uvnitř funkce nastavVek. Jak tomu zabránit? Můžeme použít něco, čemu se říká globální proměnná.

Poznámka: Globální proměnné se v Pythonu příliš nepoužívají. Vedou totiž ke špatnému strukturování programu, k tzv. špagetovému kódu. Zde je používám jen k vysvětlení komplexnějších záležitostí — jinak se jich, prosím, vyvarujte.

Tím, že řekneme interpreteru, že je proměnná globální (pomocí výrazu jako je global vek), mu řekneme, že má být použita proměnná mimo funkci namísto vytváření nové lokální proměnné. (Globální je tedy opakem k lokální.) Program můžeme přepsat například takto:

# korektni, ale ne zcela spravny postup, jak to udelat

vek = 0



def nastavVek(v):

    global vek

    vek = v



nastavVek(100)

print vek

# vypise 100

Jakmile si přečtete něco o objektech (níže), zjistíte, že mnohem vhodnější by bylo vytvořit objekt s položkou vek a metodou nastavVek. V kapitole o složitějších datových typech také uvidíte lepší příklady funkcí měnících prostředí, v němž se vyskytují.

Co říci o opravdových funkcích? Co je to ve skutečnosti funkce? Matematické funkce jsou trošku jako „stroje“, které na základě nějakého vstupu vypočítají výsledek. Pro stejný vstup vždy vracejí stejnou hodnotu. Kupříkladu:

def mocnina(x):

    return x * x

Je to to samé jako matematická funkce f(x) = x2. Chová se to jako hezká funkce, která závisí jen na svém vstupu, nemění žádným způsobem prostředí, v němž běží.

Nastínil jsem dva způsoby tvorby funkcí: V jednom případě se jedná spíše o proceduru, funkce nevrací žádný výsledek; v druhém případě se v podstatě jedná o matematickou funkci, taková funkce nedělá (plus mínus) kromě vracení výsledku nic jiného. Samozřejmě může existovat něco mezi těmito dvěma extrémy, ale pokud funkce mění své okolí, mělo by být jasné, že to dělá. Lze to naznačit například odlišným pojmenováním funkce — „čistá“ funkce se může jmenovat mocnina, kdežto v názvu hybrida mezi funkcí a procedurou se může vyskytovat rozkazovací způsob, třeba nastavVek.

Více přísad — datové struktury

Nyní již toho víte docela dost: Jak zajistit vstup i výstup programu, jak strukturovat komplikovanější algoritmy (programy), jak provádět aritmetické výpočty; to nejlepší ale stále ještě nepřišlo.

Jaké přísady jsme dosud ve svých programech používali? Čísla a řetězce. Nudné? Přidejme tedy další, zajímavější přísady.

Datové struktury jsou přísady, které strukturují data. (Opravdu velké překvapení…) Obyčejné číslo nevypadá, že by mělo příliš struktury, že? Řekněme ale, že bychom chtěli zahrnout více čísel do jedné přísady — ta by pak měla nějakou strukturu. Můžeme chtít třeba seznam čísel. To není těžké:

[3, 6, 78, 93]

Seznamy jsem zmínil už v kapitole o cyklech, ale moc jsem toho o nich neprozradil. Takže už jste viděli, jak takový seznam vytvořit; je to prostě seznam prvků oddělených čárkami, uzavřený v hranatých závorkách.

Podívejme se nyní na příklad ukazující výpočet prvočísel (čísel dělitelných jen sebou samými a jedničkou):

# Vypocet vsech prvocisel mensich nez 1000

# (Neni to nejlepsi zpusob, ale...)



vysledek = [1]

kandidati = range(3, 1000)

zaklad = 2

soucin = zaklad



while kandidati:

    while soucin < 1000:

        if soucin in kandidati:

            kandidati.remove(soucin)

        soucin = soucin + zaklad

    vysledek.append(zaklad)

    zaklad = kandidati[0]

    soucin = zaklad

    del kandidati[0]



vysledek.append(zaklad)

print vysledek

Novinky v tomto příkladu…

  1. Vestavěná funkce range ve skutečnosti vrací obyčejný seznam. (Zahrnuje první číslo z intervalu, poslední nikoliv.)
  2. Seznam může být použit jako proměnná obsahující pravdivostní hodnotu. Neprázdný seznam je ekvivalentní hodnotě true (pravda), prázdný seznam odpovídá nepravděfalse. Takže while kandidati ve skutečnosti znamená „dokud není seznam pojmenovaný kandidati prázdný“, respektive „dokud jsou nějací kandidáti“.
  3. Můžete napsat if nejakyPrvek in nejakySeznam pro kontrolu, zda je prvek obsažen v seznamu.
  4. Můžete napsat nejakySeznam.remove(nejakyPrvek) pro odstranění prvku nejakyPrvek ze seznamu nejakySeznam.
  5. Můžete připojit prvek na konec seznamu pomocí příkazu nejakySeznam.append(neco). Sice můžete použít i operátor + (například nejakySeznam = nejakySeznam + [neco]), ale není to to samé.
  6. K prvku seznamu můžete přistupovat prostřednictvím čísla jeho pozice v seznamu (kupodivu má první prvek seznamu číslo 0) uvedeného v hranatých závorkách za jménem seznamu. Takže nejakySeznam[3] je čtvtých prvkem seznamu nejakySeznam. (Více o tomto tématu níže.)
  7. Můžete mazat proměnné pomocí klíčového slova del. To může být také (jako v tomto případě) ke smazání prvku seznamu. Tedy del nejakySeznam[0] smaže první prvek seznamu nejakySeznam. Pokud bylo obsahem seznamu [1, 2, 3] před mazáním, po mazání to bude [2, 3].

Před vysvětlením tajemství okolo seznamů ještě objasním výše uvedený příklad.

Příklad výše je variací na velice starý algoritmus nazývaný „Erasthenovo síto“. Uvažujme množinu (v našem případě seznam) potenciálních prvočísel a poté z něj systematicky odstraňujme čísla, o nichž víme, že nejsou prvočísly. Jak to víme? Tato čísla jsou součinem dvou jiných čísel.

Začínáme se seznamem čísel [2..999] — víme, že jednička je prvočíslo (nebo není, záleží na tom, koho se zeptáte) a chceme znát všechna prvočísla menší než tisíc. (Ve skutečnosti je náš seznam jen [3..999], ale dvojka je také kandidátem na prvočíselnost, je to náš první zaklad.) Máme také seznam nazvaný vysledek, který v každé chvíli obsahuje aktuální seznam výsledků. Na začátku obsahuje jen jedničku. Ještě máme proměnnou zaklad. V každé iteraci („kole“) algoritmu odstraníme všechna čísla, která jsou násobky tohoto základu (nejmenšího kandidáta na prvočíselnost). Po každé iteraci víme, že nejmenší zbylé číslo je prvočíslo (všechna čísla, která byla násobkem menších čísel již byla odstraněna — chápete?). Přidáme jej k výsledkům, nastavíme jej jako základ a odstraníme jej ze seznamu potenciálních prvočísel (abychom s ním opět nepočítali). Jakmile bude seznam kandidátů na prvočíselnost prázdný, seznam výsledků bude obsahovat všechna prvočísla. Chytré, ne?

Věci k zamyšlení: Co je zvláštního na první iteraci? V ní je základem dvojka, která je odstraněna z „prosívání“? Proč? Proč se to neděje ostatním základům? Můžeme si být jisti, že soucin je v seznamu potenciálních prvočísel vždy, když jej chceme odstranit? Proč?

Co nyní? Jistě… Indexování. A rozřezávání. To jsou způsoby, jak v Pythonu získat jednotlivé prvky seznamu. Už jste viděli v akci obyčejné indexování. Je to docela jednoduché. Už jsem o tom uvedl vše vyjma jedné věci: Záporné indexy slouží k přistupování k prvkům seznamu od jeho konce. Takže nejakySeznam[-1] vrací poslední prvek seznamu nejakySeznam, nejakySeznam[-2] vrací předposlední prvek a tak dále.

Rozřezávání by pro vás mělo být nové. Je podobné indexování, ale jeho výsledkem není jen jeden prvek seznamu, nýbrž hned několik prvků seznamu. Jak se to dělá? Takto:

jidlo = ["sunka", "sunka", "vejce", "salamy", "sunka"]



print jidlo[2:4]

# Vypise "['vejce', 'salamy']"

Více abstrakce — objekty a objektově orientované programování

Pokud bylo někdy nějaké slovní spojení neustále omíláno stále dokola, pak to bylo nepochybně „objektově orientované programování“.

Jak název této kapitoly naznačuje, objektově orientované programování je jen jiným způsobem, jak abstrahovat detaily. Procedury abstrahují jednoduché výroky do komplexnějších operací tím, že jim dávají jméno. V OOP nemanipulujeme pouze s operacemi, ale rovnou s objekty. (To je ale překvapení, že?) Pokud bychom psali třeba program na smažení šunky, namísto psaní spousty procedur pro vypořádání se s teplotou, časem, přísadami,… bychom vše sdružili do jednoho objektu pro šunku. Možná bychom mohli mít i objekty pro troubu, hodiny,… Pak by věci jako teplota byly položkami objektu pro šunku, zatímco čas by spadal pod zvláštní objekt pro čas. Aby náš program něco dělal, mohli bychom své objekty naučit metodám; například trouba by mohla umět péct šunku atd.

Takže jak to uděláme v Pythonu? Objekt nemůžeme udělat přímo. Namísto vytváření trouby vytváříme recept, který udává, jaké trouby bývají. Tento recept popisuje třídu objektů, které nazýváme troubami. Velice jednoduchá třída pro troubu by mohla být:

class Trouba:

    def vlozSunku(self, sunka):

        self.sunka = sunka



    def vratSunku(self):

        return self.sunka

Nevypadá to divně?

Novinky v tomto příkladu…

  1. Třídy objektů jsou definovány klíčovým slovem class.
  2. Jména tříd obvykle začínají velkým písmenem, zatímco názvy funkcí a proměnných (a metod a položek) začínají malým písmenem.
  3. Metody (například funkce nebo operace, které umí objekty provádět) se definují úplně normálně, ale jsou obsaženy uvnitř v bloku třídy.
  4. Všechny metody objektu by měly mít první parametr nazvaný self (nebo tak nějak…). Důvod (snad) vyplyne na povrch za moment.
  5. K položkám a metodám objektu se přistupuje takto: mojeSunka.teplota = 2 nebo dilbert.bud_prijemny().

Tipuji, že stále je ohledně příkladu ještě něco nejasného. Například ta záležitost ohledně self. A když už máme recept na objekt (například třídu), jak vytvoříme konkrétní objekt?

Nejprve se vypořádejme s druhým problémem. Objekt vytvoříme voláním jména třídy jakoby to byla funkce:

mojeTrouba = Trouba()

mojeTrouba nyní obsahuje objekt Trouba, který se obvykle nazývá instance třídy Trouba. Předpokládejme, že jsme si vytvořili i třídu Sunka; pak můžeme udělat něco takového:

mojeSunka = Sunka()

mojeTrouba.vlozSunku(mojeSunka)

mojeTrouba.sunka by nyní měla obsahovat objekt mojeSunka. Jak to? Protože když voláme nějakou metodu objektu, první parametr, obvykle nazývaný self, vždy obsahuje objekt samotný. (Chytré, ne?) Takže řádek self.sunka = sunka nastavuje položku sunka konkrétního objektu Trouba na hodnotu parametru sunka. Všimněte si, že se jedná o dvě různé věci, ačkoliv se v tomto příkladu obě jmenují sunka.

Odpověď ke Cvičení 3

Zde je velice stručná verze algoritmu:

def eukleides(a, b):

    while b:

        a, b = b, a % b

    return a

Poznámky

[1] Recept na slavnostní šunkový salát podle digitální kuchařky Hormel Foods.


Instant Hacking (Magnus Lie Hetland) / CC BY 3.0