Níže uvedený text pochází z prvního vydání. Nad tímto textem se nachází aktuální stav po revizi směřující k druhému vydání.
O čem si budeme povídat?
Čtvrtý element programování do hry zapojuje použití modulů (viz Společné vlastnosti programů). Ve skutečnosti není naprosto nezbytné a i bez něj, s použitím toho, o čem jsme se zatím bavili, můžete vytvořit docela působivé programy. Jenomže s tím, jak se program stává větším, stává se stále obtížnějším sledování toho, co a kde se v něm děje. Potřebujeme použít způsob, který by nám umožnil potlačit nutnost uvažování v některých detailech tak, abychom mohli uvažovat o řešeném problému a abychom nemuseli řešit všechny detaily, které souvisejí se způsobem fungování počítače. Python, BASIC a další jazyky to do jisté míry řeší již svými zabudovanými schopnostmi — nemusíme se například zabývat detaily počítačového technického vybavení (hardware), nemusíme se zabývat tím, jak se čtou stisky jednotlivých kláves na klávesnici a podobně.
Používání modulů má programátorovi umožnit rozšiřování
zabudovaných schopností jazyka. Zabývá se obalováním kousků programů do
modulů tak, abychom je mohli využít v našich programech. První formou modulu
byl podprogram, což byl blok kódu, na který bylo možno skočit
(něčím jako příkaz GOTO, o kterém jsme se zmínili v kapitole o
větvení). Jakmile byl blok dokončen, bylo možné skočit zpět do místa odkud
byl volán. Tato specifická podoba modularity je známa pod pojmy
procedura nebo funkce. V jazyce Python a v některých
dalších jazycích se slovo modul spojilo se specifickým významem, o
kterém si zachvíli něco povíme. Ale nejdříve se podívejme podrobněji na
funkce.
Dříve, než se budeme zabývat tím, jak můžeme funkci vytvořit, podívejme se, jak používáme velké množství funkcí, které se k libovolnému programovacímu jazyku dodávají (často se dodávají v podobě takzvané knihovny).
Použití některých funkcí a seznam dalších funkcí jsme již viděli, když jsme se bavili o operátorech. Nyní se zaměříme na to, co mají všechny funkce společné a jak je můžeme používat v našich programech. Základní struktura funkce vypadá následovně:
Promenna = nejakaFunkce(argument, dalsi, atd...)
To znamená, že proměnné Promenna je přiřazena hodnota,
která je získána jako výsledek volání funkce. Funkce může mít žádný nebo
více argumentů, ke kterým se chová jako k interním proměnným.
Funkce mohou uvnitř svého kódu volat další funkce. Vezměme si některé
příklady v našich vybraných jazycích a podívejme se, jak to funguje:
Tato funkce vrací m znaků z řetězce str$,
počínaje pozicí n. (Vzpomeňte si, že když v jazyce BASIC
uvedeme za jméno proměnné '$', říkáme tím, že pracujeme s
řetězcem.)
den$ = "pondělí úterý středa" PRINT "Dnes je";MID$(den$,8,6)
Vytiskne se "Dnes je úterý".
Tato funkce vrací obsah proměnné prostředí (environment
variable), jejíž jméno je uložené v str$.
PRINT ENVIRON$("PATH")
Vytiskne obsah proměnné prostředí PATH, která se například
v systému DOS obvykle nastavuje uvnitř souboru autoexec.bat.
Vrací délku seznamu L.
set a {"první" "druhý" "třetí"} # seznam s třemi prvky
puts [llength $a] # výsledkem bude řetězec '3'
Poznámka: V jazyce Tcl je funkcí téměř vše (Tcl místo pojmu funkce upřednostňuje pojem příkaz). Vede to sice k poněkud podivné syntaxi, ale naopak pro počítač je díky tomu zpracování Tcl programů velmi snadné. To je velmi důležité, protože zkratka Tcl znamená Tool Control Language (doslova jazyk pro řízení nebo ovládání nástrojů). Jazyk Tcl byl navržen tak, aby jej bylo možno zabudovat do jiných programů a aby v nich plnil úlohu makro jazyka, podobně jako se Visual Basic for Applications (VBA) používá v produktech firmy Microsoft. Ve skutečnosti můžete stejným způsobem do něčeho jiného vestavět i Python, ale jazyk Tcl je unikátní v tom, že myšlenka pro jeho zabudování do jiných prostředků byla při jeho návrhu od samého počátku prioritní.
x = 2 # použijeme 2 jako hodnotu základu for y in range(0,11): print pow(x,y) # umocní 2 na y, tj. na 0 až 10
V tomto příkladu generujeme hodnoty y od 0 do 10 a voláme
zabudovanou funkci pow() s dvěma argumenty: x a
y. Při každém volání jsou aktuální hodnoty x a
y dosazeny do volání funkce a výsledek je vytištěn.
Poznámka: Operátor pro umocňování ** je ekvivalentem
funkce pow().
Další užitečnou zabudovanou funkcí jazyka Python je funkce
dir(). Když jí předáme jméno modulu, vrátí nám seznam platných
jmen — často jsou to jména funkcí —, které modul obsahuje.
Vyzkoušejte si ji pro vypsání seznamu jmen zabudovaných funkcí:
print dir(__builtins__)
Poznámka: Pokud budete chtít učinit totéž pro libovolný jiný modul,
musíte jej nejdříve zpřístupnit příkazem import. V opačném
případě si Python bude stěžovat, že jméno modulu nezná.
Dříve, než se pustíme do dalších věcí, měli bychom si o modulech v jazyce Python říci více podrobností.
Python je extrémně rozšiřovatelný jazyk (stejně, jako je i Tcl) v tom
smyslu, že můžete přidávat nové možnosti tím, že provedete
import potřebných modulů. Zakrátko si ukážeme, jak můžeme
moduly vytvářet. Ale nejdříve si trochu pohrajeme z některými standardními
moduly, se kterými se Python již dodává.
S modulem sys jsme se již potkali v okamžiku, kdy jsme z
kódu v jazyce Python volali funkci exit za účelem ukončení
programu. Modul obsahuje celou řadu dalších užitečných funkcí. Abychom k nim
získali přístup, musíme provést import sys:
import sys # zpřístupní vnitřní funkce sys.exit() # uvádíme předponu 'sys'
Pokud víme, že budeme funkce modulu používat velmi často a pokud nemají stejná jména jako funkce, které jsme již dříve importovali nebo vytvořili, pak můžeme psát:
from sys import * # import všech jmen z modulu sys exit() # nyní nemusíme uvádět předponu 'sys'
Uvedeným způsobem můžeme importovat libovolné pythonovské moduly. Týká se to i modulů, které si sami vytvoříte. Za okamžik si ukážeme, jak na to. Ale nejdříve si uděláme krátkou přehlídku některých standardních modulů jazyka Python a představíme si něco z toho, co nabízejí:
| Jméno modulu | Popis |
|---|---|
sys |
Umožňuje interakci se systémem Python:
|
os |
Umožňuje interakci s operačním systémem:
|
string |
Umožňuje manipulaci s řetězci:
|
re |
Umožňuje manipulaci s řetězci předepsanou regulárními výrazy, jaké se
používají v systému Unix:
|
math |
Zpřístupňuje řadu matematických funkcí:
|
time |
Funkce pro práci s časem a datem:
|
Uvedené funkce představují pouze špičku ledovce. V distribuci systému Python se nacházejí doslova tucty modulů a mnoho dalších si můžete stáhnout z Internetu (jejich dobrým zdrojem jsou stránky Vaults of Parnassus). Nahlédněte do dokumentace a najdete informace o funcích pro přístup na Internet, pro grafiku, pro tvorbu databází, atd.
Je důležité si uvědomit, že u většiny programovacích jazyků jsou tyto funkce buď zabudované nebo jsou součástí jejich standardní knihovny. Než začnete psát nějakou funkci, vždycky si v dokumentaci ověřte, zda již náhodou neexistuje. Tím jsme se pěkně dostali k tématu…
Nyní již víme, jak používat existující funkce. Ale jak můžeme vytvořit novou funkci? Jednoduše ji definujeme. To znamená, že napíšeme příkaz, který interpretu říká, že definujeme blok kódu, který má být na požádání vsunut na jiná místa v našem programu. (Myslí se tím vsunutí funkčnosti a nikoliv rozepsání v podobě zdrojového textu.)
Vytvořme funkci, která nám vytiskne tabulku násobků libovolného čísla, které zadáme jako argument. V jazyce BASIC by to vypadalo takto:
SUB NASOBKY (N%)
FOR I = 1 TO 12
PRINT I; "x"; N%; "="; I * N%
NEXT I
END SUB
Funkci můžeme volat tímto způsobem:
PRINT "Tady je tabulka násobků číslem 7 ..." NASOBKY(7)
Poznámka: V uvedené funkci jsme definovali parametr
označený N% a při jejím volání jsme předali argument o
hodnotě 7. Když je funkce zavolána, pak její lokální proměnná
N% získá hodnotu 7. U funkce můžeme definovat
tolik parametrů, kolik potřebujeme. Při jejím volání ale musí být každému
parametru přiřazena hodnota. Některé programovací jazyky vám umožňují
definovat přednastavené hodnoty parametrů (default value), takže
pokud není jejich hodnota při volání určena, použije se přednastavená
hodnota. (V odborné
terminologii se používá pojem implicitní hodnota parametru, která
se použije, pokud hodnota parametru není explicitně určena.)
Později si ukážeme, jak se to dělá v jazyce Python.
V jazyce Python by funkce pro tisk tabulky násobků vypadala takto:
def nasobky(n):
for i in range(1, 13):
print "%d x %d = %d" % (i, n, i*n)
A volali bychom ji takto:
print "Tady je tabulka násobků číslem 9 ..." nasobky(9)
Povšimněte si, že tyto funkce nevracejí žádnou hodnotu. Takovým funkcím
se v některých jazycích říká procedury. Povšimněte si, že verze
příkladu v jazyce BASIC používá klíčové slovo SUB a ne
FUNCTION. Jde o zkratku slova subroutine (v češtině
podprogram), což je nyní již málo používaný termín z dob
programování v assembleru (tj. v jazyce symbolických instrukcí). V jazyce BASIC se jím
označují funkce, které nevracejí hodnotu. Python používá klíčové slovo
def, které je zkrácenou formou slova define (definuj).
To, co následuje, se považuje za definici funkce.
Vzpomínáte si, že jsem se zmínil o použití přednastavených hodnot? Příklad rozumného použití přednastavené hodnoty parametru si ukážeme na funkci, která vrací jméno dne v týdnu. Pokud ji zavoláme bez zadání argumentu, budeme mít na mysli dnešní den. V ostatních případech bude argumentem pořadové číslo dne v týdnu:
# Hodnota dne -1 znamená 'dnes'.
def denTydne(CisloDne = -1):
dny = ['pondělí', 'úterý',
'středa', 'čtvrtek',
'pátek', 'sobota', 'neděle']
# Zkontrolujeme, zda nejde o přednastavenou hodnotu.
if CisloDne == -1:
# Použij funkce modulu time k získání současného času
# -- viz tabulka uvedená výše a viz oficiální dokumentace modulu.
import time
cas = time.localtime(time.time())
CisloDne = cas[6]
return dny[CisloDne]
Poznámka: Modul time potřebujeme použít jen v
případě, kdy se uplatní přednastavená hodnota parametru. Operaci
import proto odložíme až na dobu, kdy modul skutečně
potřebujeme. V případech, kdy přednastavená hodnota není nikdy použita,
pak bude náš program o něco výkonnější.
Nyní můžeme funkci zavolat:
print "Dnes je %s." % denTydne()
# Zapamatujte si, že v počítačové řeči začínáme nulou.
# Nula odpovídá prvnímu dni -- pondělí.
print "Třetím dnem je %s." % denTydne(2)
Vraťme se opět k násobení. Co kdybychom chtěli definovat funkci, která vrací hodnoty násobení v podobě pole čísel? V jazyce BASIC by to vypadalo takto:
FUNCTION NASOBKY% (N%)
DIM HODNOTY(12) AS INTEGER
FOR I = 1 to 12
HODNOTY(I) = I*N%
NEXT I
RETURN HODNOTY
END FUNCTION
A v jazyce Python by to vypadalo následovně:
def nasobky(n):
# Vytvoř prázdný seznam
hodnoty = []
for i in range(1, 13):
hodnoty.append(i * n)
return hodnoty
Psát konkrétně něco takového by bylo pěkně hloupé, protože je prostě
jednodušší v okamžiku požadavku na hodnotu vypočítat
i * n. Ale doufám, že jste pochopili, kam tím míříme.
Funkce, která počítá slova v řetězci, již může být mnohem praktičtější.
Můžete ji použít i pro zjištění počtu slov v souboru tím, že sečtete počty
slov pro jednotlivé řádky.
Kód by mohl vypadat nějak takto:
def pocetSlov(s):
seznam = split(s) # seznam, kde prvkem je vždy slovo
return len(seznam) # vrátíme počet prvků seznamu
for radek in soubor:
celkem = celkem + pocetSlov(radek) # sečti počty za každý řádek
print "Soubor má %d slov." % celkem
Pokud byste uvedený kód vyzkoušeli, zjistili byste, že nefunguje. To, co jsme si právě předvedli, je běžná technika návrhu programu. Spočívá v načrtnutí našich představ o tom, jak by kód měl vypadat, ale netrápíme se s tím, aby byl kód absolutně správný. Takovému zápisu se někdy říká pseudo kód nebo — při dodržení formálnějšího stylu — zápis v jazyce pro popis programu (z anglického Program Description Language nebo zkráceně PDL).
Až se blíže podíváme na práci se soubory a s řetězci (v další části kurzu), vrátíme se k tomuto příkladu a vytvoříme jeho funkční verzi.
Funkce můžeme, samozřejmě, vytvářet i v Tcl. Používáme k tomu příkaz
proc:
proc nasobky {m} {
for {set i 1} {$i <= 12} {incr i} {
lappend hodnoty [expr $i * $m]
}
return $hodnoty
}
Všimněte si, že použitím Tcl příkazu lappend automaticky
vytvoříme seznam nazvaný hodnoty a začneme do něj přidávat
prvky.
Jazyk Tcl je ve způsobu zacházení s funkcemi poněkud odlišný od jiných jazyků. Mohli
jste si všimnout, že volané příkazy jsou zabudovanými funkcemi jazyka Tcl. V
jazyce Tcl je každý příkaz, který napíšete na příkazový řádek, ve
skutečnosti voláním funkce. Většina ostatních jazyků definuje množinu
klíčových slov, jako například for, while,
if/else a další. V jazyce Tcl se všechna tato klíčová slova pro
řídicí struktury transformují na příkazy nebo na funkce. Tato skutečnost má
zajímavý, matoucí a velmi mocný efekt. Umožňuje nám změnit chování
zabudovaných řídicích struktur — například takto:
set i 3
while {$i < 10} {
puts $i
set i [expr $i + 1]
}
Ve shodě s naším očekáváním, tento kód vytiskne čísla od 3 do 9 (což je
o 1 méně, než 10). Ale nadefinujme si nyní naši vlastní verzi příkazu
while:
proc while {x y} {
puts "Toto je nyní můj příkaz while"
}
set i 3
while {$i < 10} {
puts $i
set i [expr $i + 1]
}
Uvedený kód pak neudělá nic víc, než že vytiskne zprávu "Toto je nyní
můj příkaz while". Podmínkový výraz a posloupnost příkazů jsou
ignorovány, protože Tcl se na ně dívá jako na parametry funkce
while a naše
nová funkce while tyto parametry sice očekává, ale
ignoruje je. Takže tady vidíte, jak lze v jazyce Tcl definovat procedury a
jak je lze zneužít pro vytvoření velmi matoucích programů. Nedělejte to,
pokud pro to nemáte velmi závažný důvod!
Takže nyní již umíme vytvářet naše vlastní funkce a volat je z jiných částí našeho programu. Vytváření vlastních funkcí nám ušetří hodně psaní a — což je mnohem důležitější — učiní naše programy srozumitelnějšími. Je to dáno tím, že do vytvořených funkcí ukryjeme některé detaily, na které pak při jejich použití nemusíme myslet. (Tento princip obalování složitých úseků programu funkcemi se z docela zřejmých důvodů nazývá ukrývání informací [information hiding].) Ale jak můžeme tyto funkce používat v jiných programech? Vytvoříme modul.
V jazyce Python není modul ničím zvláštním. Je to jednoduše prostý textový soubor s příkazy programu v jazyce Python. Obvykle jsou to definice funkcí. Takže, když napíšeme…
from sys import *
tak tím jakoby okopírujeme obsah sys.py do našeho programu.
Je to téměř jako kdybychom text modulu přenesli přes schránku (clipboard)
operacemi Kopírovat a Vložit (cut and paste). (No, ve skutečnosti to takhle
není, ale koncepčně to můžeme tak chápat.) Překladače některých jazyků (z
význačných jmenujme C++) kopírují na základě požadavků obsah souborů s
moduly do aktuálního programu doslova[1].
Takže si to zrekapitulujme. Modul vznikne vytvořením pythonovského
souboru (.py), který obsahuje funkce, které chceme používat v
jiných programech. Potom jednoduše provedeme import našeho
modulu přesně stejným způsobem, jako to děláme se standardními moduly.
Snadné, co? Tak pojďme na to.
Okopírujte si níže uvedenou funkci a uložte ji do svého souboru se jménem
nasobky.py.
def tisk_tabulky(nasobitel):
print "--- Tisk tabulky násobků číslem %d ---" % nasobitel
for n in range(1, 13):
print "%d x %d = %d" % (n, nasobitel, n * nasobitel)
Nyní na příkazový řádek systému Python napište:
>>> import nasobky >>> nasobky.tisk_tabulky(12)
No vida! Právě jste vytvořili modul a použili jste ho.
Důležitá poznámka: Pokud jste Python nespustili ze stejného adresáře, ve kterém je uložen váš soubor nasobky.py, pak jej Python možná nenašel a zahlásil chybu. Pokud tomu tak skutečně je, můžete vytvořit proměnnou prostředí nazvanou PYTHONPATH, která obsahuje seznam adresářů, ve kterých se budou hledat moduly (tedy ty, které nejsou dodávány jako standardní spolu se sytémem Python).
Způsob vytváření proměnných prostředí je závislý na platformě. Předpokládám, že příslušné operace buď znáte nebo si je umíte zjistit.
A jak je na tom BASIC? Tady to bude trochu složitější. Ve variantě QBASIC
a v dalších starších variantách koncepce modulu vůbec neexistuje. Potřebný
kód z dřívějších projektů musíte okopírovat do aktuálního projektu pomocí
funkcí textového editoru. Ale ve variantě Visual Basic koncept modulu
existuje. Modul můžeme načíst příkazem menu File|Open Module...
v integrovaném vývojovém prostředí (IDE). Pro moduly jazyka Visual
Basic existují určitá omezení v tom smyslu, že do něj nemůžeme umístit
cokoliv. Do detailů se zde pouštět nebudeme, protože se zde tímto jazykem
nezabýváme.
Poznámka: Pokud chcete experimentovat, můžete si ze serveru firmy Microsoft zdarma stáhnout ořezanou verzi jazyka Visual Basic, která je známá jako COM Controls Edition (CCE). Ořezaná verze VB je také součástí instalace Windows 98, 2000 a IE5. Říká se jí VBScript a pracuje se soubory končícími .vbs.
A nakonec se podíváme na Tcl. Tento jazyk si, jako vždycky, zvolil ke znovupoužití modulů (místo modulu se upřednostňuje název knihovna) trochu jinou, nicméně zajímavou cestu.
Na nejjednodušší úrovni můžete jednoduše vytvořit soubor s Tcl funkcemi
— stejně, jako to děláme v jazyce Python. V našem programu pak funkce
v daném souboru můžeme zpřístupnit operací source. Tím
interpretu řekneme, aby přečetl daný soubor. V něm uložený kód se tak
zpřístupní k dalšímu použití. Ale v Tcl existuje i zajímavější možnost.
Naše soubory můžeme po vytvoření umístit do zvoleného adresáře a poté
spustíme příkaz mk_index. Ten vytvoří rejstřík (index) všech
funkcí a souborů v podadresáři. V našem programu pak jednoduše voláme
požadovanou funkci a interpret Tcl — když zjistí, že není dostupná
— automaticky prohledá rejstřík. Nalezne v knihovně odpovídající
zdrojový soubor, zpřístupní jeho kód operací source a
požadovanou funkci provede.
Jakmile byla funkce již jednou zpřístupněna, zůstane přístupná i nadále, takže její následné volání nevede k vyšší výkonnostní režii. Jediný problém spočívá v tom, že programátor nemůže definovat více než jednu funkci se stejným jménem. Popsaný rys jazyka Tcl je znám jako autoloading (automatické načítání nebo automatické zavádění).
V další části se podíváme na soubory a na zpracování textu. A potom, jak jsme si slíbili, se znovu podíváme na problém počítání slov v souboru. Ve skutečnosti si nakonec pro naše potřeby vytvoříme modul s funkcemi pro zpracování textu.
Zapamatujte si
def.SUB nebo FUN, v jazyce Tcl se používá
proc.Pokud vás napadne, co by se dalo na překladu této kapitoly vylepšit, zašlete e-mail odklepnutím tohoto odkazu. Tím bude do subjektu dopisu automaticky vložena informace o jméně a verzi tohoto HTML dokumentu.
$Id: cztutfunc.html,v 1.2 2004/05/14 10:22:46 prikryl Exp $