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 $