O čem si budeme povídat?
Z hlediska způsobu zpracování chyb je z našich tří jazyků VBScript ten nejbizarn>jší. Je to dáno tím, že staví na základech jazyka BASIC, který patří k jedn>m z prvních programovacích jazyků (kolem roku 1963). Způsob zpracování chyb v jazyce VBScript patří k t>m místům, ze kterých je zmín>né d>dictví jasn> vid>t. Pro naše účely to není špatné, protože mi to dává příležitost k vysv>tlení, proč VBScript používá práv> takový přístup. Vysv>tlíme si historii způsobu zpracování chyb od jazyka BASIC, přes Visual Basic, až k VBScript. Poté se podíváme na mnohem modern>jší přístup, který ukázkovým způsobem využívají JavaScript a Python.
V tradiční verzi jazyka BASIC byly se na všech řádcích programu psala
čísla řádků. Přesun řízení se provád>l skokem na určitý řádek použitím
příkazu GOTO. (Příklad jsme si ukázali v rámci tématu V>tvení.) Byl to v podstat> jediný možný způsob
řízení. V prostředí s takovými vlastnostmi byl b>žný způsob ošetřování chyb
založen na deklaraci prom>nné ERRORCODE, ve které se ukládala
číselná hodnota. Když se v programu vyskytla chyba, nastavil se obsah
prom>nné ERRORCODE na odpovídající hodnotu — nepodařilo
se otevřít soubor, neslučitelnost typů, přetečení operátoru, a podobn>.
Uvedený přístup vedl k psaní kódu, který vypadal podobn>, jako následující úsek fiktivního programu:
1010 LET DATA = INPUT FILE 1020 CALL FUNKCE_PRO_ZPRACOVANI_DAT 1030 IF NOT ERRORCODE = 0 GOTO 5000 1040 CALL JINA_FUNKCE 1050 IF NOT ERRORCODE = 0 GOTO 5000 1060 REM POKRACUJ VE ZPRACOVANI TAKTO... ... 5000 IF ERRORCODE = 1 GOTO 5100 5010 IF ERRORCODE = 2 GOTO 5200 5020 REM DALSI PRIKAZY IF ... 5100 REM ZDE ZPRACUJ CHYBOVY KOD 1. ... 5200 REM ZDE ZPRACUJ CHYBOVY KOD 2.
Vidíme, že skoro polovina hlavního programu se zabývá zjišťováním, zda nenastala chyba. Časem byl zaveden o n>co elegantn>jší mechanismus, ve kterém se detekce chyba a jejich ošetření částečn> přesunulo do interpretu jazyka. Vypadal n>jak takto:
1010 LET DATA = INPUTFILE 1020 ON ERROR GOTO 5000 1030 CALL FUNKCE_PRO_ZPRACOVANI_DAT 1040 CALL JINA_FUNKCE ... 5000 IF ERRORCODE = 1 GOTO 5100 5010 IF ERRORCODE = 2 GOTO 5200
K popisu umíst>ní kódu pro ošetření chyby zde stačí jeden řádek. Pokud
funkce narazila na chybu, musela i nadále nastavovat hodnotu prom>nné
ERRORCODE, ale velmi se zjednodušil zápis (a čtení!) kódu.
No a co to má společného s námi? Je to docela prosté. Tento způsob zpracování chyb i nadále používá Visual Basic, ačkoliv čísla řádků byla nahrazena uživatelsky přív>tív>jšími náv>štími. VBScript — jako potomek jazyka Visual Basic — používá výrazn> ořezanou verzi téhož mechanismu. To ve svém důsledku znamená, že nám VBScript dává na vybranou: buď budeme ošeřovat chyby lokáln>, nebo je budeme zcela ignorovat.
Pokud se rozhodneme pro ignorování chyb, zapíšeme to takto:
On Error Goto 0 ' 0 říká "nikam neskákej"
NejakaFunkce()
NejakaJinaFunkce()
...
Pokud se rozhodneme pro lokální ošetření chyb, použijeme zápis:
On Error Resume Next
NejakaFunkce()
If Err.Number = 42 Then
' tady ošetři chybu
NejakaJinaFunkce()
...
Takový zápis vypadá trochu zpátečnicky. Ve skutečnosti prost> odráží výše popsaný historický proces.
V případ> výskytu chyby se interpret standardn> zachová tak, že uživateli
zobrazí zprávu a zastaví provád>ní programu. Práv> toto se stane, pokud při
určování způsobu zpracování chyby použijeme zápis Goto 0. To
znamená, že zápisem Goto 0 vypínáme lokální řízení a říkáme
interpretu, aby se zachoval obvyklým způsobem.
Předpis pro zpracování chyby obsahující Resume Next nám
buď dovolí předstírat, že chyba vůbec nenastala, nebo si můžeme otestovat
objekt pro popis chyby (je pojmenován Err). Zajímá nás zejména
jeho číselná složka Number. (Jde o naprosto
stejnou techniku, jako výše ukázané testování ERRORCODE.) Objekt
Err nese ješt> další informační položky, které nám mohou pomoci
vyrovnat se s nastalou situací mén> katastrofickým způsobem, než je zastavení
programu. Můžeme například zjistit, v jakém míst> k chyb> došlo (v jakém
objektu, v jaké funkci a podobn>). Můžeme také získat textový popis chyby,
který můžeme uživateli vypsat jako součást hlášení o chyb>, nebo jej můžeme
zapsat do log souboru. Typ chyby můžeme v objektu Err zm>nit
použitím jeho metody Raise. Tuto metodu můžeme použít i při
generování našich vlastních chyb, které nastaly v našich vlastních
funkcích.
Jako příklad mechanismu ošetřování chyby v jazyce VBScript is uveďme případ, kdy dochází k d>lení nulou:
<script type="text/vbscript">
Dim x, y, vysledek
x = CInt(InputBox("Zadejte d>lence: "))
y = CInt(InputBox("Zadejte d>litele: "))
On Error Resume Next
vysledek = x/y
If Err.Number = 11 Then ' D>lení nulou
vysledek = Null
End If
On Error GoTo 0 ' ošetřování chyb op>t vypneme
If VarType(vysledek) = vbNull Then
MsgBox "CHYBA: Operace nemohla být provedena."
Else
MsgBox CStr(x) & " d>leno " & CStr(y) & " je rovno " & CStr(vysledek)
End If
</script>
Upřímn> řečeno, uvedený přístup moc p>kný není. A zatímco obdivování dávné historie může být balzámem pro duši, moderní programovací jazyky, včetn> jazyků Python a JavaScript, nabízejí mnohem elegantn>jší způsoby ošetřování chyb. Podívejme se, o jaké mechanismy jde.
V modern>jších programovacích prostředích se vyvinul alternativní způsob práce s chybami. Je znám pod pojmem ošetření výjimek a je založen na tom, že funkce vrhají (throw) nebo, jinými slovy, vyvolávají (raise) výjimky (exception [iksepšn]). Systém si pak zajistí vyskočení z aktuálního bloku kódu na nejbližší blok pro ošetření výjimky. V systému se nachází také blok kódu, který zachytí (catch) všechny výjimky, které dosud nebyly zpracovány n>kde jinde. Poté obvykle zobrazí chybové hlášení a ukončí b>h aplikace.
K velkým výhodám tohoto stylu ošetřování chyb patří mnohem lepší čitelnost hlavní funkčnosti programu. Je to dáno tím, že nedochází k mísení s kódem pro ošetřování chyb. Jinými slovy, v bloku kódu si můžeme číst aniž bychom byli jakkoliv nuceni číst kód pro ošetřování chyb.
Podívejme se, jak se uvedený styl programování používá v praxi.
Blok kódu pro ošetření výjimek se trochu podobá bloku
if...then...else:
try: # Zde se umístí hlavní část kódu programu. except TypVyjimky: # Zde se bude zpracovávat jmenovaná výjimka. except JinyTypVyjimky: # Zde se ošetřuje jiná výjimka. else: # Zde umístíme úklidový kód, který se provede # v případ>, že nenastane žádná výjimka.
Python se pokouší provád>t příkazy mezi příkazy try a prvním
except. Pokud dojde k chyb>, provád>ní příkazů v bloku za
try se zastaví a skočí se dolů k příkazu except.
Postupn> se procházejí jednotlivé příkazy except, dokud se
nenajde ten, který odpovídá typu chyby (neboli výjimky). Pokud se
nalezne, provede se blok bezprostředn> následujícího kódu. Pokud se nenalezne
žádný odpovídající příkaz except, předává se nalezená chyba dál,
do dalších (vyšších) úrovní programu. Pokud
není nalezen odpovídající except, dostane se chyba až na úroveň
interpretu jazyka Python, který chybu zachytí, zobrazí chybové hlášení a
zastaví provád>ní programu. V našich programech jsme zatím pozorovali práv>
takový projev, protože
jsme zatím neum>li chybu zachytit a zpracovat sami.
Pokud v bloku try k žádným chybám nedojde, pak se provede blok
za else. Ale v praxi se této možnosti využívá velmi zřídka.
Poznamenejme, že příkaz except, u kterého není uveden žádný typ
chyby, zachytí chyby všech typů, které dosud nebyly zpracovány.
Využívání této formy příkazu se ale obecn> nepovažuje za dobrý nápad. Výjimku
ovšem představuje jeho používání v nejvyšší úrovni programu, kdy chceme
zabránit tomu, aby Python uživateli zobrazil velmi technickou podobu chybového
hlášení. Obecná podoba příkazu except nám v tomto případ> umožní
odchytit všechny dosud neošetřené chyby a zobrazit přív>tiv>jší hlášení o
ukončování programu.
Za zmínku stojí, že součástí instalace Pythonu je i modul
traceback, který nám umožní extrahovat různé doplňkové informace
o zdroji chyby. To se nám může hodit při vytváření log souboru a pro podobné
akce. Modulem traceback se zde zabývat nebudeme. V případ>
potřeby naleznete popis jeho vlastností a použití ve standardní dokumentaci
modulů.
A jak to vše skutečn> funguje si ukážeme na příkladu:
hodnota = raw_input("Zadej delitele: ")
try:
hodnota = int(hodnota)
print "42 / %d = %d" % (hodnota, 42 / hodnota)
except ValueError:
print "Hodnotu nelze prevest na cele cislo."
except ZeroDivisionError:
print "Neni povolena nulova hodnota."
except:
print "Stalo se neco neocekavaneho."
else:
print "Program skoncil uspesne."
Pokud program spustíme a místo čísla zadáme n>jaký řet>zec, zobrazí se
zpráva vypisovaná ve v>tvi ValueError (chyba hodnoty). Pokud zadáme nulu,
zobrazí se zpráva pro ZeroDivisionError (chyba při d>lení nulou). Pokud
zadáme platné číslo, zobrazí se výsledek a zpráva o úsp>šném ukončení
programu.
Existuje ješt> jeden typ bloku, který souvisí s výjimkami. Umožňuje
zapsat kód pro úklid provád>ný i poté, co nastala chyba. Nazývá se
try...finally (try [tray] = zkus, pokus se vykonat; finally [fajnly] =
nakonec) a typicky se používá pro zavírání souborů, vyprazdňování
vyrovnávacích pam>tí (buffer) na disk a podobn>. Blok finally
je proveden vždy jako poslední nezávisle na tom, co se stane v sekci
try. Pokud
nenastane výjimka, prost> se provede. Pokud nastane výjimka, zapamatuje se
její objekt, kód bloku finally se provede a zapamatovaná
výjimka se znovu vyvolá.
try: # Kód, související s účelem programu. finally: # V této části provádíme úklidové akce nezávisle # na tom, zda v bloku try nastala chyba či nikoliv.
Síla této konstrukce se projeví při kombinaci s blokem
try/except. Konkrétní volba pořadí zanoření t>chto bloků
nepřináší významné výhody. Pořadí zpracování příkazů zůstává v obou případech
stejné. Osobn> používám blok try/finally obvykle jako vn>jší,
protože si tím připomínám, že se blok v>tve finally
provede jako poslední. Ale z pohledu Pythonu je to jedno. Příklad:
print 'Start programu.'
try:
try:
data = file('data.dat')
hodnota = int(data.readline().split()[2])
print 'Hodnota je %d.' % (hodnota/(42-hodnota))
except ZeroDivisionError:
print 'Hodnota byla 42.'
finally:
data.close()
print 'Konec programu.'
V tomto případ> dojde k uzavření souboru vždy, nezávisle na tom, zda v
bloku try/except vznikne výjimka. Všimn>te si odlišnosti
chování ve vztahu k v>tvi else v konstrukci
try/except/else, protože blok v else se zavolá
jen v případ>, kdy nedojde k žádné výjimce. To by znamenalo, že by
nedošlo k uzavření souboru. Pokud bychom zase kód pro uzavření souboru
umístili jednoduše mimo konstrukci try/except, pak by se soubor
neuzavřel v případ>, kdy by nastala jiná výjimka, než
ZeroDivisionError. Takže pouze konstrukce
try/finally zajistí, že k uzavření souboru dojde
vždy.
Poznámka překladatele: V souboru data.dat se očekává
alespoň jeden řádek, který obsahuje alespoň tři slova (řet>zce nerozd>lené
mezerami) a třetí slovo má charakter čísla. Příklad obsahu:
xxx yyy 40
Zadáním hodnoty 42 (do souboru) vyvoláme výjimku
ZeroDivisionError. Pokud místo čísla zadáme například řet>zec
ccc, vznikne jiná výjimka (ValueError) související
s tím, že se řet>zec nedaří převést na číslo. Pokud místo čísla neuvedeme
vůbec nic, vznikne při následném volání metody split() k
vygenerování kratšího seznamu, takže nebude existovat položka s indexem 2. V
takovém případ> vznikne výjimka IndexError.
Osobn> se mi nelíbí otvírání souboru na jiné úrovni (v zanořeném
try), než na jaké se provádí uzavírání — i když to
funguje. Podle mého názoru by se soubor m>l zavírat na stejné úrovni v kódu,
na které byl otevřen.
Platí to obecn>, ale nejvýrazn>ji je to vid>t v případ>, kdy jedna z akcí (otevření/zavření souboru) je umíst>na uvnitř funkce a druhá vn>. Například funkce, které dostává jako argument otevřený soubor, by jej nem>la zavírat. Ono to sice může fungovat naprosto bez problémů, ale může dojít ke zmatkům v naší hlav>, když si čteme zdrojový text. Důvod spočívá v tom, že při zápisu používání funkce je tato akce skryta našemu zraku a nemusíme si uv>domit, co se vevnitř d>je. Výjimku představují situace, kdy funkce svým jménem napovídá, že se předaný soubor uvnitř otevře, respektive uzavře.
Pokud tedy toto pravidlo selského rozumu napasujeme na výše
uvedený příklad, pak osobn> dávám přednost následujícímu zápisu příkladu
(navíc přidán příkaz print za uzavření souboru, abychom
zviditelnili provedení bloku kódu):
print 'Start programu.'
try:
data = file('data.dat')
try:
hodnota = int(data.readline().split()[2])
print 'Hodnota je %d.' % (hodnota/(42-hodnota))
except ZeroDivisionError:
print 'Hodnota byla 42.'
finally:
data.close()
print 'Soubor uzavřen.'
print 'Konec programu.'
Je tady ale ješt> jeden zádrhel. Pokud by navíc selhalo i otvírání
zouboru data.dat, dojde k výjimce prom>nná data
nebude napln>na (případn> se váže na předchozí hodnotu). To znamená, že v
sekci finally, ve kterém se budeme pokoušet o volání metody
close() objektu, který neexistuje. Proto je lepší zapsat:
print 'Start programu.'
data = file('data.dat')
try:
try:
hodnota = int(data.readline().split()[2])
print 'Hodnota je %d.' % (hodnota/(42-hodnota))
except ZeroDivisionError:
print 'Hodnota byla 42.'
finally:
data.close()
print 'Soubor uzavřen.'
print 'Konec programu.'
V takovém případ> je ovšem sporné už samotné použití
try/finally, protože v případ>, kdy se soubor nepovede otevřít,
nedostaneme se vůbec do následující konstrukce. Zavírání souboru stejn> v
takovém případ> není možné (viz předchozí odstavec). Pokud se soubor povede
otevřít, nepotřebujeme uzavírání souboru vkládat do bloku
finally. Osobn> bych se proto přiklonil k naprosto jednoduchému
řešení bez vn>jší konstrukce try/finally.
print 'Start programu.'
data = file('data.dat')
try:
hodnota = int(data.readline().split()[2])
print 'Hodnota je %d.' % (hodnota/(42-hodnota))
except ZeroDivisionError:
print 'Hodnota byla 42.'
except:
print u'Nastala jiná výjimka.'
data.close()
print 'Konec programu.'
Záv>r: Původní příklad není tak jednoduchý, jak vypadá.
Jakým způsobem můžeme generovat výjimky — dejme tomu uvnitř modulu
—, které má zachytit n>kdo jiný? V jazyce Python je pro tento případ
vyhrazeno klíčové slovo raise:
delenec = 42
delitel = input('Jakou hodnotou chcete d>lit číslo 42? ')
if delitel == 0:
raise ZeroDivisionError()
Tento kód vygeneruje výjimku ZeroDivisionError, která může
být zachycena v bloku try/except. Zbytku programu se to jeví
naprosto stejn>, jako kdyby chybu vygeneroval přímo Python. Klíčovým slovem
raise se předepisuje také předávání chyby zevnitř bloku
except do vyšších úrovní programu. Při výskytu chyby můžeme například
chtít provést n>jakou lokální akci, dejme tomu zapsat záznam do log souboru,
ale poté chceme, aby se o dalších akcích rozhodlo na vyšších úrovních
programu. Použití může vypadat takto:
logsoubor = file('errorlog.txt', 'w')
def f(hodnota):
try:
return 127 / (42-hodnota)
except ZeroDivisionError:
logsoubor.write('Hodnota byla 42.')
raise
try:
f(42)
except ZeroDivisionError:
print 'Nastala chyba. Zkuste znovu.'
Povšimn>te si, jak funkce f() zachytává chybu, zapisuje
zprávu do souboru se záznamem o chyb> a poté předává zachycenou výjimku ke
zpracování v bloku kódu, který se nachází ve vn>jší, obalující konstrukci
try/except.
Poznámka překladatele: S log soubory, tedy se soubory
určenými pro záznam (protokolování) chyb a zvláštních stavů, se v>tšinou
zachází tak, že se záznamy neustále připisují na konec. Prakticky to
znamená, že by se log soubor m>l otvírat pro zápis za konec souboru, tedy v
režimu append (druhý parametr s hodnotou 'a').
Další zásada vyplývá ze skutečnosti, že u otevřeného souboru není zaručeno, že je veškerý zapisovaný obsah skutečn> fyzicky uložen na disku. Pokud toho chceme dosáhnout, pak můžeme ve vhodných okamžicích provád>t takzvané vyprázdn>ní vyrovnávací pam>ti (flush).
Při zápisu do log souboru s chybami, kdy se předpokládá nízký počet zápisů, bývá praktičt>jší log soubor otevřít před každým zápisem a poté ho hned zavřít. Pokud aplikace havaruje, máme jistotu, že se neztratilo n>kolik posledních zápisů.
Ve výše uvedeném příklad> je log soubor otevřen na začátku a dokonce jsme jej zapom>li zavřít. Při výskytu chyby se původní obsah přepisuje, takže budeme mít zapsán jen poslední záznam. V mnoha jednoduchých případech to stačí, ale proč bychom to nemohli ud>lat pořádn>ji, když to není o moc složit>jší:
def f(hodnota):
try:
return 127 / (42-hodnota)
except ZeroDivisionError:
logsoubor = file('errorlog.txt', 'a') # Otevřeme pro připsání na konec,
logsoubor.write('Hodnota byla 42.\n') # zapíšeme hodnotu
logsoubor.close() # a soubor uzavřeme.
raise
try:
f(42)
except ZeroDivisionError:
print u'Nastalo d>lení nulou. Zkuste znovu.'
V praktických případech často používáme jediný log soubor a chceme do n>j
zapisovat na více místech v programu. Museli bychom tedy na více místech
opakovat výše uvedené okomentované řádky. Problém by nastal v situaci, kdy
se rozhodneme například zm>nit jméno log souboru. V takovém případ> by nám
m>lo v hlav> varovn> zasvítit pravidlo DRY z anglického Do not
Repeat Yourself, čili voln> Neopakujte se. V>c jednoduše
vyřešíme tím, že si pro zápis na konec log souboru vytvoříme vlastní funkci log().
S jejím využitím pak výsledek bude vypadat n>jak takto:
def log(zprava):
logsoubor = file('errorlog.txt', 'a') # Otevřeme pro připsání na konec,
logsoubor.write(zprava) # zapíšeme hodnotu
logsoubor.close() # a soubor uzavřeme.
def f(hodnota):
try:
return 127 / (42-hodnota)
except ZeroDivisionError:
log('Hodnota byla 42.\n') # Zápis zprávy do log souboru.
raise
try:
f(42)
except ZeroDivisionError:
print u'Nastalo d>lení nulou. Zkuste znovu.'
V tomto okamžiku byste si mohli říci. Proč bych za každou zprávu
nepřidával automaticky přechod na nový řádek přímo ve funkci
log()? Nedoporučuji to. Uv>domte si, že v takovém případ>
byste se zbavili možnosti zapisovat postupn> n>kolika voláními funkce více
hodnot na jeden řádek log souboru. Místo toho je vhodn>jší vytvořit další,
specializovan>jší funkci, která využívá výše definované, obecn>jší funkce
log(). Speciální funkce může například do log souboru zapisovat
i datum, čas a jmého přihlášeného uživatele:
def log(zprava):
logsoubor = file('errorlog.txt', 'a') # Otevřeme pro připsání na konec,
logsoubor.write(zprava) # zapíšeme hodnotu
logsoubor.close() # a soubor uzavřeme.
def logErr(text):
import time # Importujeme potřebné moduly.
import getpass
tim = time.strftime('%c') # Získáme časovou značku.
usr = getpass.getuser() # Získáme jméno uživatele.
log('%s %s: %s\n' % (tim, usr, text)) # Zapíšeme zformátovaný řádek.
def f(hodnota):
try:
return 127 / (42-hodnota)
except ZeroDivisionError:
logErr('Hodnota byla 42.') # Zápis zprávy do log souboru.
raise
try:
f(42)
except ZeroDivisionError:
print u'Nastalo d>lení nulou. Zkuste znovu.'
Za účelem zjemn>ní řízení našeho programu (nebo diagnostiky chyb) můžeme
definovat své vlastní typy výjimek. Činíme tak prostřednictvím nových tříd
výjimek. (S definicemi tříd jsme se krátce seznámili rámci tématu Data, datové typy a prom>nné a podrobn>ji se
s nimi setkáme ješt> pozd>ji v kapitole v>nované objektov> orientovanému programování.) Pro tento
účel obvykle definujeme třídu velmi prostou, která nedefinuje žádný další
obsah a která je pouze odvozena od standardní bázové třídy
Exception. Používá se jako chytré náv>ští, které se dá
rozpoznávat v příkazech except. Spokojme se s následujícím
stručným příkladem:
class BrokenError(Exception): pass try: raise BrokenError except BrokenError: print u'Narazili jsme na chybu při zpracování.'
Poznámka překladatele: Vzhledem k následující autorov> poznámce jsem ponechal původní anglický identifikátor. Připojuji se k výzv> dodržovat níže uvedenou konvenci.
Povšimn>te si, že jsme při tvorb> jména použili konvenci, kdy se na konec
jména třídy dává přípona "Error" (čili chyba). Povšimn>te si, že
d>díme chování obecné třídy Exception ([iksepšn],
výjimka) tím, že její jméno uvedeme do závorek za jménem definované
třídy. K d>dičnosti se podrobn>ji dostaneme v kapitole v>nované objektov> orientovanému programování.
Ješt> poslední poznámka k části týkající se generování chyb. Prozatím
jsme pro předčasné ukončování našich
programů provád>li importováním modulu sys a voláním jeho
funkce exit(). Jiný způsob, kterým dosáhneme naprosto stejného
výsledku, spočívá ve vyvolání výjimky SystemExit:
>>> raise SystemExit
Hlavní výhoda tohoto přístupu spočívá v tom, že nemusíme nejdříve provést
import sys.
Poznámka překladatele: Osobn> se k tomuto postupu
moc nepřikláním. Volání funkce exit() je známé i z jiných
jazyků a jiným čtenářům vašeho zdrojového textu může volání
sys.exit() připadat přirozen>jší.
V jazyce JavaScript se zpracování chyb provádí velmi podobn>, jako v
jazyce Python. Jen místo pythonovských klíčových slov try,
except a raise se používají klíčová slova
try, catch ([keč], chytit) a
throw (vrhnout, hodit).
Ukážeme si pár příkladů, ale principy zůstávají naprosto stejné jako v
jazyce Python. V jazyce JavaScript ale nemáme konstrukci
try/finally.
Zachytávání chyb v bloku kódu se předepisuje klíčovým slovem
try a sadou příkazů catch tém>ř stejn>, jako v
Pythonu:
<script type="text/javascript">
try {
var x = NeexistujiciFunkce();
document.write(x);
}
catch(err) {
document.write("Došlo k chyb>.");
}
</script>
V jazyce Python jsme k vyvolání chyby používali klíčové slovo
raise. V jazyce JavaScript používáme podobným způsobem
throw(). Také v jazyce JavaScript si můžeme vytvořit vlastní
typy chyb, jako v Pythonu. Ale mnohem jednodušší způsob spočívá v použití
řet>zce.
<script type="text/javascript">
try {
throw("Nová chyba");
}
catch(e) {
if (e == "Nová chyba")
document.write("Zachytili jsme novou chybu.");
else
document.write("Nenastala nová chyba.");
}
</script>
Poznámka překladatele: Řet>zce se pro výjimky používaly dříve i v jazyce Python. Z důvodů zp>tné kompatibility jsou dosud podporovány, ale u nových programů se jejich používání nedoporučuje. Do budoucna se plánuje odstran>ní této možnosti.
To je vše, co si o zpracování chyb řekneme. V tématech pro pokročilé uvidíte použití mechanismu pro zpracování chyb v praxi, spolu s použitím dalších základních konceptů, jako jsou posloupnosti, cykly a v>tvení. V tomto okamžiku již máte k dispozici všechny podstatné nástroje, které potřebujete pro vytváření mocných programů. Možná byste si teď m>li zkusit n>jaké vlastní programy vytvořit. Stačí pár, jen abyste dostali popisované mechanismy do hlavy před tím, než se pustíme do dalších témat. Pár nám>tů:
Abyste se s výše uvedenými úkoly vyrovnali, budete muset použít všechny
rysy jazyka, se kterými jsme se dosud seznámili, a možná i pár dodávaných
modulů. Nezapomeňte občas nahlédnout do dokumentace. Pravd>podobn> v ní
najdete pár v>cí, které vám ulehčí práci. Nezapomínejte taky na užitečnost
interaktivního režimu (>>>). Zkoušejte si v n>m nové v>ci,
dokud nepochopíte, jak fungují. Teprve poté přeneste získané znalosti do
vašeho programu. Tímto způsobem pracují i profesionálové. A co je taky
důležité, dobře se bavte!
Nashledanou v části pro pokročilé :-)
Zapamatujte si
if.except
a v JavaScript pomocí catch.raise, v JavaScript pomocí throw.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: cztuterrors.html,v 1.8 2005/10/20 20:55:24 petr Exp $