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 $