Programování s využitím modulů

O čem si budeme povídat?

Co to je modul?

Č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 najít způsob jak potlačit nutnost uvažování o n>kterých detailech, abychom mohli uvažovat o řešeném problému a abychom nemuseli řešit vše, co souvisí s fungováním počítače. Python, VBScript a JavaScript 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 konkrétní 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 s přesn>ji vymezeným významem, o kterém si za chvíli n>co povíme. Ale nejdříve se podívejme podrobn>ji na funkce.

Používání funkcí

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 volání 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. Ve v>tšin> programovacích jazyků (i když ne ve všech) musíme v zápisu volání funkce uvád>t závorky i v případ>, kdy nemá žádné argumenty.

Vezm>me si n>které příklady v našich vybraných jazycích a podívejme se, jak to funguje:

VBScript: Mid(retezec, start, delka)

Tato funkce vrací delka znaků z řet>zce retezec, počínaje pozicí start.

<script type="text/vbscript">
Dim cas
cas = "ráno večer odpoledne"
MsgBox "Dobrý " &  Mid(cas, 6, 5)
</script>

Zobrazí se "Dobrý večer". Poznamenejme, že u VBScript se argumenty funkce nemusí uzavírat do závorek. Stačí odd>lení mezerou, jak jsme učinili při volání MsgBox. Ovšem pokud kombinujeme volání dvou funkcí (jako v našem případ>), pak vnitřní funkce musí používat závorky. Moje rada zní: pokud jste na pochybách, používejte závorky.

VBScript: Date

Tato funkce vrací aktuální systémové datum.

<script type="text/vbscript">
MsgBox Date
</script>

Asi už se k tomu nedá víc dodat. Snad jen, že existuje celá skupina funkcí pro práci s datem, které umožňují získat informaci o dni, týdnu, hodin> atd.

JavaScript: startString.replace(searchString, newString)

Vrací nový řet>zec, který vznikne z řet>zce startString nahrazením podřet>zce searchString novým řet>zcem newString.

<script type="text/javascript">
var r, s = "Dlouhá a vít>zná cesta.";
document.write("Originál = " + s + "<BR>");
r = s.replace("Dlouhá", "Krátká");
document.write("Výsledek = " + r);
</script>

Poznámka: V jazyce JavaScript se tém>ř všude setkáváme se speciálním typem funkce, které říkáme metoda. Metodou rozumíme funkci, která je spojena s objektem (viz dříve probírané téma Data, datové typy a prom>nné a viz více detailů dále). Za poznámku zde stojí především to, že uvedená funkce je připojena k řet>zci s tečkovým operátorem. Chápe se to tak, že s je řet>zcem, nad kterým se provádí náhrada.

Není to nic nového. Už od začátku této učebnice používáme pro zobrazení výstupu v našich javascriptových programech metodu write() objektu document (zapisujeme document.write()). Zatím jsem se pouze nezmiňoval o důvodech, které jsou s touto formou zápisu spojeny.

Python: pow(x,y)

Funkce pow() umocňuje základ x na y.

>>> 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 předáváme jí dva argumenty: x a y. Aktuální hodnoty x a y jsou do volání funkce pow() dosazeny při každé obrátce cyklu a výsledek je pokaždé vytišt>n.

Poznámka: Python definuje také operátor pro umocňování **, který je ekvivalentem funkce pow().

Python: dir(m)

Další užitečnou zabudovanou funkcí jazyka Python je funkce dir(). Když jí předáme jméno modulu, vrátí nám seznam všech jmen, která modul exportuje, včetn> všech prom>nných a funkcí, které můžeme použít. O modulech jsme se až do tohoto okamžiku nezmiňovali, ale Python se dodává spolu s velkým množstvím modulů. Vypišme si funkcí dir() seznam jmen zabudovaných funkcí:

print dir(__builtins__)

Poznámka 1: builtins je jedním z on>ch magických slov systému Python. Takže je op>t obklopeno dvojicemi znaků podtržení — dv> podtržení na každé stran>.

Poznámka 2: Pokud budete chtít funkci dir() použít 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á.

>>> import sys
>>> dir(sys)

Vzpomeňte si, že s modulem sys jsme se setkali již v našich prvních tématech, v>novaných posloupnostem. Ve výstupním seznamu posledního volání funkce dir() byste si m>li všimnout jména naší staré známé funkce exit().

Dříve, než se pustíme do dalších v>cí, m>li bychom si o modulech v jazyce Python říci více podrobností.

Používání modulů

Python je extrémn> rozšiřovatelný jazyk 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á.

sys

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í — jak jsme si mohli povšimnout ve výstupu funkce dir ve výše uvedeném příkladu. Abychom k nim získali přístup, musíme provést příkaz import sys:

import sys         # zpřístupní vnitřní funkce
print sys.path()   # ukaž, kde Python hledá moduly
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 
print path()       # nyní nemusíme uvád>t předponu 'sys'
exit()

Pokud chceme z modulu používat jen pár funkcí, pak bývá bezpečn>jší použít následující obrat:

from sys import path, exit # importujeme jen potřebné
print path()               # používáme bez předpony 'sys'
exit()

Povšimn>te si, že za jmény vybraných funkcí neuvádíme závorky. Pokud bychom tak učinili, bylo by to chápáno jako pokus o spušt>ní funkcí. Uvádíme pouze jméno funkce.

Poznámka překladatele: příkaz from...import... je obecný a dá se použít pro zveřejn>ní různých jmen definovaných v modulu, nejen jmen funkcí. Vynechávání závorek je proto logické i z tohoto pohledu.

Na záv>r bych vám rád ukázal trik, který vám může ušetřit psaní. Pokud používáte modul s velmi dlouhým jménem, můžete jej při importování přejmenovat. Příklad:

import SimpleXMLRPCServer as m
m.SimpleXMLRPCRequestHandler()

Pythonu jsme zde řekli, aby považoval m za zkratku pro modul SimpleXMLRPCServer. Pokud nyní chceme použít n>jakou funkci z tohoto modulu, budeme před ni psát pouze m., což je mnohem kratší.

Další moduly jazyka Python a jejich obsah

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 moduluPopis
sys Umožňuje interakci se systémem Python:
  • exit() — ukončení b>hu programu
  • argv — seznam argumentů z příkazového řádku
  • path — seznam cest prohledávaných při práci s moduly
  • ps1 — m>ní vyzývací řet>zec '>>>' příkazového řádku interpretu jazyka Python
os Umožňuje interakci s operačním systémem:
  • name — zkratka charakterizující používaný operační systém; užitečná při psaní přenositelných programů
  • system — provedení příkazu systému
  • mkdir — vytvoření adresáře
  • getcwd — zjistí současný pracovní adresář (z anglického get current working directory)
re Umožňuje manipulaci s řet>zci předepsanou regulárními výrazy, jaké se používají v systému Unix:
  • search — hledej vzorek kdekoliv v řet>zci
  • match — hledej pouze od začátku řet>zce
  • findall — nalezne všechny výskyty vzorku v řet>zci
  • split — rozd>l na podřet>zce, které jsou odd>leny zadaným vzorkem
  • sub, subn — náhrada řet>zců
math Zpřístupňuje řadu matematických funkcí:
  • sin, cos, atd. — trigonometrické funkce
  • log, log10 — přirozený a dekadický logaritmus
  • ceil, floor — zaokrouhlení na celé číslo nahoru a dolů
  • pi, e — konstanty
time Funkce pro práci s časem a datem:
  • time — vrací současný čas (vyjádřený v sekundách)
  • gmtime — převod času v sekundách na UTC (tj. na čas v univerzálních časových souřadnicích — znám>jší pod zkratkou GMT z anglického Greenwich Mean Time, tedy greenwichský [grinidžský] čas)
  • localtime — převod do lokálního času (tj. posunutého vůči UTC o celé hodiny)
  • mktime — opačná operace k localtime
  • sleep — pozastaví b>h programu na zadaný počet sekund
random Generátory náhodných čísel — užitečné nejen pro programování her!
  • randint — generování náhodného čísla mezi dv>mi hranicemi (včetn>)
  • sample — generování náhodného podseznamu z jiného seznamu
  • seed — počáteční nastavení klíče pro generování čísel

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…

Definice našich vlastních funkcí

Nyní již víme, jak používat existující funkce a moduly. 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ůže být na požádání proveden na jiném míst> našeho programu.

Nejdříve VBScript

Vytvořme funkci, která nám vytiskne tabulku násobků libovolného čísla, které zadáme jako argument. V jazyce VBScript by to vypadalo takto:

<script type="text/vbscript">
Sub Nasobky(N)
Dim I
For I = 1 To 12
    MsgBox I & " x " & N & " = " & I * N
Next 
End Sub
</script>

Za značkou uvád>jící blok v jazyce VBScript jsme použili klíčové slovo Sub (jako Subroutine, čili podprogram) a celou definice jsme ukončili klíčovými slovy End Sub. V kulatých závorkách jsme uvedli seznam formálních parametrů. Uvnitř se nachází b>žný kód v jazyce VBScript až na to, že se parametry chápou jako kdyby to byly již definované lokální prom>nné.

Nov> definovanou funkci můžeme od tohoto okamžiku volat třeba takto:

<script type="text/vbscript">
MsgBox "Následují hodnoty násobků čísla 7..."
Nasobky 7
</script>

Poznámka 1: 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.) Za chvíli si ukážeme, jak se to d>lá v jazyce Python.

Poznámka 2: V definici funkce je parametr N uzavřen v kulatých závorkách, ale — jak je u VBScript zvykem — při volání funkce jsme kulaté závorky nepoužili.

Uvedená funkce nevrací žádnou hodnotu a je ve skutečnosti tím, čemu se říká procedura. Je to jednoduše funkce, která nevrací hodnotu. Jazyk VBScript procedury a funkce rozlišuje. Syntakticky tak činí používáním jiného klíčového slova v definici. Podívejme se na zápis skutečné funkce zapsané v jazyke VBScript, která vrací tabulku násobku jako jeden dlouhý řet>zec:

<script type="text/vbscript">
Function TabulkaNasobku(N)
    Dim I, S
    S = "Tabulka násobků čísla " & N & ":" & vbNewLine
    For I = 1 to 12
        S = S & I & " x " & N & " = " & I * N & vbNewLine
    Next
    TabulkaNasobku = S
End Function

Dim Nasobitel
Nasobitel = InputBox("Zadejte násobitele, pro který má být tabulka generována:?")
MsgBox TabulkaNasobku(Nasobitel)
</script>

Zápis funkce (používá klíčové slovo Function) je tém>ř stejný, jako zápis procedury (klíčové slovo Sub). Ale všimn>te si, že uvnitř definice funkce musíme navíc výsledek přiřadit jménu funkce. Jakmile funkce skončí, vrátí hodnotu, která byla jejímu jménu přiřazena:

    ...
    TabulkaNasobku = S
End Function

Pokud neprovedeme přiřazení konkrétní hodnoty, funkce vrátí implicitní hodnotu (default), což je obvykle nula nebo prázdný řet>zec.

Povšimn>te si také, že jsme na řádku MsgBox museli argument uzavřít do kulatých závorek. Kdybychom tak neučinili, funkce MsgBox by neum>la rozlišit, zda se má Nasobitel vytisknout, nebo zda se má předat funkci TabulkaNasobku jako první argument.

A teď v Pythonu

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)

Poznámka překladatele: Místo funkce range() by se m>la přednostn> používat funkce efektivn>jší funkce xrange(). Funkce range() nejdříve vygeneruje celý seznam čísel a teprve ten se prochází v cyklu for. Funkce xrange() existenci seznamu při použití v cyklu for simuluje (vrací vždy další hodnotu), ale seznam nevytváří. Důležité je to zejména při generování velkého rozsahu indexů. Ve vzdálené budoucnosti se implementace range() zm>ní na n>co podobného xrange(). Do té doby používejte přednostn> xrange(). V jednoduchých případech funguje stejn> jako range(), v extrémních případech je výkonn>jší a pam>ťov> nenáročná.

Povšimn>te si, že v jazyce Python se mezi procedurami a funkcemi ned>lá rozdíl. Při jejich definici se používá stejné klíčové slovo def. Jediný rozdíl spočívá v tom, že se k návratu funkční hodnoty používá příkaz return:

def tabulkaNasobku(n):
    s = ""
    for i in range(1, 13):
        s = s + "%d x %d = %d\n" % (i, n, i*n)
    return s

Jak vidíte, je to velmi jednoduché. Výsledek prost> vrátíme příkazem return. Výsledek funkce si můžeme vytisknout:

print tabulkaNasobku(7)

Implicitní hodnoty

Možná si vzpomenete, že jsem se již zmínil o použití implicitních hodnot (default). U funkcí můžeme předepsat implicitní hodnotu parametru, který nebyl při volání funkce zadán přímo (explicitn>). Smysluplnou ukázku tohoto rysu může představovat funkce, která vrací den v týdnu. Pokud ji zavoláme bez parametru, míníme tím dnes. V ostatních případech předáváme požadovaný den číslem:

# -*- coding: cp1250 -*-
import time

# Hodnota dne -1 znamená 'dnes'.
def denTydne(CisloDne = -1):
    # Výčet dnů musí být uveden v pořadí, v jakém je používá Python.
    dny = [u'pond>lí', u'úterý',
           u'středa', u'čtvrtek', 
           u'pátek', u'sobota', u'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 oficiální dokumentace modulu.
        cas = time.localtime(time.time())
        CisloDne = cas[6] # získáme číslo dne
    return dny[CisloDne]

Poznámka: Modul time potřebujeme použít jen v případ>, kdy se uplatní přednastavená (implicitní) hodnota parametru. Operaci import bychom proto mohli odložit až na dobu, kdy modul skutečn> potřebujeme. V případech, kdy přednastavená hodnota není nikdy použita, by pak náš program mohl být o n>co výkonn>jší. Ale úspora výkonu by byla velmi malá a navíc bychom porušili konvenci, která říká, že import máme uvád>t na začátku souboru. V podobných případech rad>ji dáme přednost vyšší přehlednosti zdrojového textu před zanedbateln> vyšším výkonem při b>hu.

Poznámka překladatele: Úvodní řádek # -*- coding: cp1250 -*- říká, že zdrojový text v souboru byl pořízen v kódování 1250 (přesn>ji windows-1250, ale Python vyžaduje uvedený tvar zápisu). Pokud jej neuvedeme, bude si Python při překladu st>žovat, že nalezl znaky s kódem v>tším než 128 (tj. mimo ASCII).

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)

Počítání slov

Jako další příklad funkce, která vrací hodnotu, si uvedeme funkci počítající slova v zadaném řet>zci. Mohli bychom ji použít i pro zjišt>ní počtu slov v souboru tak, že bychom sečetli počty slov za jednotlivé řádky. Kód by mohl vypadat n>jak takto:

def pocetSlov(s):
    s = s.strip()      # odstraníme mezery na začátku a na konci
    seznam = s.split() # seznam, kde prvkem je vždy slovo
    return len(seznam) # vrátíme počet prvků seznamu

Tím jsme nadefinovali funkci, která využívá n>které metody zabudovaného typu řet>zec. Zmínili jsme se o n>m v kapitole Data, datové typy a prom>nné. Teď bychom funkci rádi použili n>jak takto:

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 učebnice), vrátíme se k tomuto příkladu a přepíšeme jej do funkční podoby.

Funkce v JavaScript

V jazyce JavaScript můžeme vytvářet funkce samozřejm> také. Používáme k tomu příkaz function:

<script type="text/javascript">
var i, hodnoty;

function nasobky(m) {
    var vysledky = new Array();
    for (i = 1; i <= 12; ++i) {
        vysledky[i] = i * m;
        }
    return vysledky;
}
// Použití funkce.
hodnoty = nasobky(8);

for (i = 1; i <= 12; ++i) {
    document.write(hodnoty[i] + "<br>");
    }
</script>

V tomto případ> není uvedená funkce příliš užitečná. Přesto doufám, že jste si všimli podobnosti její základní struktury s definicemi funkcí v jazycích Python a VBScript. Se složit>jšími funkcemi v jazyce JavaScript se setkáme v dalších částech učebnice. Zmiňme se například o tom, že v JavaScript se funkce používají jednak jako funkce a jednak k definici objektů. Zní to zmaten> a ke zmatkům zde také může docházet.

Než se pustíme do dalších v>cí, podívejme se zp>t na příklad v JavaScript, který jsme si uvedli v kapitole Konverzace s uživatelem. Práv> teď k tomu nastal ten správný čas. JavaScript jsme v n>m použili pro čtení vstupu z webového formuláře. Kód vypadal takto:

<script type="text/javascript">
function mujProgram(){
    alert("Získali jsme hodnotu " + document.formular.pole.value);
}
</script>

<form name='formular'>
<p>Zadej hodnotu a potom klikni myší mimo vstupní pole</p>
<input type='text' name='pole' onChange='mujProgram()'>
</form>

Když se na to podíváme s našimi nov> nabytými znalostmi, vidíme, že jsme nadefinovali funkci nazvanou mujProgram. Ve formuláři jsme předepsali, že se tato funkce má zavolat, když ze zm>ní obsah vstupního pole. Další vysv>tlení si uvedeme v tématu Událostmi řízené programování.

Malé varování

Možnost definovat funkce představuje mocný nástroj, protože nám to umožňuje rozšiřovat schopnosti jazyka. Můžeme dokonce zm>nit chování jazyka tím, že pro předdefinované funkce uvedeme novou definici, s novým významem (n>které jazyky to neumožňují). Obvykle se to nepovažuje za příliš dobrý nápad. Každopádn> musíme velmi pečliv> kontrolovat dopady podobného činu (za chvíli si ukážeme, jak na to). Předefinováním chování standardních funkcí daného jazyka můžeme velmi ztížit srozumitelnost zdrojových textů. Čtenář očekává, že se taková funkce chová určitým způsobem, ale vy jste toto chování zm>nili. V praxi se proto zm>na základního chování zabudovaných funkcí považuje za nevhodnou.

Jedna z možností, jak dodržet zásadu nem>nit chování zabudovaných funkcí a přitom použít jméno funkce pro naše vlastní účely, spočívá ve vložení nové definice do objektu nebo do modulu, které platnost takové funkce definují ve svém vlastním kontextu. K objektové variant> se dostaneme pozd>ji — v tématu Objektov> orientované programování. Nyní se podívejme na možnost vytvoření našich vlastních modulů.

Vytváření našich vlastních modulů

Zatím jsme si ukázali, jak můžeme 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? Odpov>ď zní — vytvoříme modul.

Moduly v jazyce Python

V jazyce Python není modul ničím zvláštním. Je to prostý textový soubor s příkazy programu v jazyce Python. Obvykle jsou to definice funkcí. Takže, když napíšeme…

import sys

tak tím interpretu jazyka Python říkáme, že má načíst obsah tohoto modulu, provést inicializaci jeho kódu a zpřístupnit jeho vygenerovaná jména pro použití v našem souboru. Je to tém>ř jako kdybychom okopírovali obsah souboru sys.py do našeho souboru například přes schránku (clipboard) operacemi Kopírovat a Vložit (copy/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 a 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. Můžeme to provést prostřednictvím editoru z IDLE, editoru Notepad (Poznámkový blok) nebo jiného editoru, který ukládá prosté textové soubory. Nepoužívejte aplikace typu textový procesor (nepoužívejte tedy například Microsoft Word nebo Microsoft WordPad), protože ty navíc do souboru ukládají všelijaké formátovací značky, kterým by Python nerozum>l.

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. Například uživatelé Windows XP mohou použít tlačítko Start a najít si informace o prom>nných prostředí. Dozví se, jak si je mohou vytvářet. Poznámka překladatele: Konkrétn> lze po stisku Start vybrat položky NastaveníOvládací panely, poklepat na ikonu Systém, přepnout se na záložku Upřesnit a stisknout tlačítko Prom>nné prostředí. Další podrobnosti viz dokumentace.

Moduly ve VBScript a v JavaScript

A jak je na tom VBScript? Tady to bude složit>jší. V samotném jazyce VBScript a v dalších starších variantách jazyka BASIC koncepce modulu vůbec neexistuje. VBScript místo toho staví na opakovaném použití kódu mezi objekty, který je založen na vytváření objektů. Dostaneme se k tomu pozd>ji. Prozatím budeme muset potřebný kód okopírovat z dřív>jších projektů do aktuálního projektu pomocí funkcí textového editoru.

Poznámka: V>tší bratr jazyka VBScript — jazyk Visual Basic — ovšem koncept modulu podporuje. 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. (Pokud chcete experimentovat, existuje (nebo alespoň tomu tak bylo) voln> dostupná verze jazyka Visual Basic, která je známa jako Visual Basic 5.0 Control Creation Edition, čili VBCCE. Dala se zdarma stáhnout ze stránek společnosti Microsoft. Pokud máte chuť na pokusy, pak více podrobností naleznete na této stránce.

JavaScript (podobn> jako VBScript) nenabízí žádný mechanismus pro používání modulů v podob> souborů s kódem. Ale existují zde určité výjimky a to ve specializovaných prostředích, kde se JavaScript nepoužívá jen uvnitř webových stránek. Jde například o Windows Script Host — viz dále.

Windows Script Host

Prozatím jsme se na jazyky VBScript a JavaScript dívali jako na jazyky pro programování uvnitř webového prohlížeče. Ten si však vynucuje určitá omezení, včetn> nemožnosti používat moduly. V prostředí Microsoft Windows však existuje i jiný způsob používání VBScript (a JavaScript), konkrétn> Windows Script Host, zkrácen> WSH. Jde o technologii firmy Microsoft, která uživatelům umožňuje programovat své osobní počítače stejným způsobem, jakým programátoři v systému DOS používali dávkové soubory (s příponou .bat). WSH poskytuje mechanismy pro čtení ze souborů, ze systémového registru, umožňuje přístup k počítačům v síti, k tiskárnám, atd.

WSH verze 2 navíc umožňuje používat (include) jiný WSH soubor, takže zavádí možnost používání modulů. Ukažme si, jak to funguje. Nejdříve si vytvoříme soubor modulu nazvaný NejakyModul.vbs, který obsahuje:

Function OdectiDvojku(N)
   OdectiDvojku = N - 2
End Function

Teď vytvoříme WSH skript, který nazveme například testModulu.wsf:

<?xml version="1.0" encoding="UTF-8" ?>

<job>
  <script language="VBScript" src="NejakyModul.vbs" />
  <script language="VBScript">
      Dim hodnota, vysledek
      WScript.Echo "Vložte číslo"
      hodnota = WScript.StdIn.ReadLine
      vysledek = OdectiDvojku(CInt(hodnota))

      WScript.Echo "Výsledek je " &amp; CStr(vysledek)
  </script>
</job>

Poznámka překladatele 1: V hlavičce XML dokumentu můžeme uvést, v jakém kódování je soubor uložen. Pokud bychom tak neučinili, pak se předpokládá, že je použito kódování UTF-8 nebo UTF-16. V případ>, že se v dokumentu vyskytují pouze ASCII znaky, je obsah dokumentu v kódování UTF-8 totožný s obsahem užívajícím kódování ASCII. U českých dokumentů se ale objeví znaky s kódem v>tším než 127 a binární podoba souboru v kódování UTF-8 se přestane podobat jiným způsobům kódování, které používají 8bitové znaky. V takovém případ> je nutné dokument skutečn> uložit v kódování UTF-8 (musí to um>t editor), protože n>které znaky budou uloženy speciálním způsobem. Alternativn> můžete v hlavičce XML dokumentu uvést jiné kódování (windows-1250, ISO-8859-2 a podobn>). Pak musíte dokument v tomto kódování skutečn> uložit. U českých dokumentů se dá obecn> říci, že je vhodn>jší v hlavičce způsob kódování dokumentu uvád>t.

Poznámka překladatele 2: Narozdíl od HTML, které pro předpis jazyka v elementu <script ...> předepisuje atribut type="text/jazyk", v XML předpisu pro WSH se uvádí forma language="jazyk", která se kdysi používala i v HTML.

Teď to můžeme spustit v DOSovém okn>:

C:\> cscript testModulu.wsf

Soubor .wsf na sebe bere podobu XML souboru. Program se nachází mezi značkami <job> a </job>. První značka <script ... /> odkazuje na soubor modulu s názem NejakyModul.vbs. Druhá značka <script ...> obsahuje náš program, který volá funkci OdectiDvojku(), definovanou v modulu NejakyModul.vbs. (První ze značek script je nepárová — její zápis končí />. Veškeré informace jsou zapsány uvnitř této značky. Naopak druhý element script je vymezen dv>mi značkami, které obklopují příslušný obsah.) Soubor s příponou .vbs obsahuje b>žný kód v jazyce VBScript bez jakýchkoliv XML či HTML značek.

Povšimn>te si příkazu WScript.Echo, ve kterém spojujeme řet>zce. Znak ampersand jsme museli zapsat zvláštním způsobem (escape), a sice &amp;, protože příkaz je součástí XML souboru. Povšimn>te si také, že ke čtení vstupu od uživatele používáme WScript.Stdin. Vzpomínáte si na poznámku o stdin a stdout v tématu Konverzace s uživatelem?

Poznámka překladatele: Pozor! Vytvořený soubor musíme skutečn> spustit přes cscript na příkazovém řádku. Určitou činnost sice můžeme pozorovat i při prostém poklepání na ikonu .wsf souboru, ale v tomto případ> by došlo ke spušt>ní v okénkovém režimu. Příkaz WScript.Echo by se projevil v podob> okna se zprávou a tlačítkem OK (Message Box). Nemáme ale vytvořenou vazbu na WScript.Stdin a nepodaří se nám zadat vstupní hodnotu. Po stisku tlačítka OK se objeví okno s chybovým hlášením a program skončí.

Stejnou techniku můžeme použít i pro JavaScript, přesn>ji řečeno pro verzi jazyka JavaScript firmy Microsoft, která se nazývá JScript. Stačí zm>nit atribut značky script, který určuje jazyk. Při použití WSH můžeme dokonce jazyky míchat. Můžeme importovat moduly v JavaScript a používat je v kódu VBScript a naopak. Jako důkaz si uvedeme odpovídající WSH skript, který přistupuje k VBScriptovému modulu z JavaScriptu:

<?xml version="1.0" encoding="UTF-8" ?>

<job>
  <script language="VBScript" src="NejakyModul.vbs" />
  <script language="JScript">
      var hodnota, vysledek;
      WScript.Echo("Vložte číslo");
      hodnota = WScript.StdIn.ReadLine();
      vysledek = OdectiDvojku(parseInt(hodnota));

      WScript.Echo("Výsledek je " + vysledek);
  </script>
</job>

Vidíte, jak moc jsou si ob> verze podobné? V>tšina chytrých v>cí se vlastn> d>lá přes objekty WScript a až na t>ch pár závorek a středníků jsou skripty v podstat> stejné.

V této učebnici nebudeme WSH používat příliš často. Přesto se k n>mu občas uchýlíme a sice v situacích, kdy nám více omezující prostředí webového prohlížeče neumožní demonstrovat n>které vlastnosti. Tak například v dalším tématu s pomocí WSH ukážeme jak lze v jazycích VBScript a JavaScript pracovat se soubory. Pokud máte zájem, pak o WSH bylo napsáno pár knih. Je mu v>nována rozsáhlá sekce webového serveru firmy Microsoft. Naleznete tam i ukázky programů, vývojové nástroje, atd. Vše se nachází zde: http://msdn.microsoft.com/scripting/.

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

Pokud vás napadne, co by se dalo na překladu této kapitoly vylepšit, zašlete e-mail odklepnutím Tím budou do dopisu automaticky vloženy informace o tomto HTML dokumentu.

$Id: cztutfunc.html,v 1.10 2005/09/15 18:23:57 petr Exp $