7
Výjimky

### Proč používat výjimky

### Základy

try:
    <příkazy>             # try blok – může vyhodit výjimku
except <jméno1>:          # pokud try blok vyhodil „jméno1“
    <příkazy>            
except <jménoN>, <prom>:  # pokud try blok vyhodil „jménoN“
    <příkazy>             #  navíc do prom něco dostaneme
else:
    <příkazy>             # pokud try blok nevyhodil výjimku

try:
    <příkazy>             # try blok – může vyhodit výjimku
finally: 
    <příkazy>             # blok finally je ale spuštěn vždy

raise <jméno>             # výjimku můžeme vyhodit “ručně”
raise <jméno> <hodnota>   #  navíc můžeme předat hodnotu

% cat problem1.py

def volana(x, y): return x / y
def volajici(x): return volana(x, 0)
print volajici(1)

% python problem1.py

Traceback (most recent call last):
  File "C:\Python22\problem1.py", line 3, in ?
    print volajici(1)
  File "C:\Python22\problem1.py", line 2, in volajici
    def volajici(x): return volana(x, 0)
  File "C:\Python22\problem1.py", line 1, in volana
    def volana(x, y): return x / y
ZeroDivisionError: integer division or modulo by zero

def bouchneTo(seznam, n):
    print seznam[n]                # pro daný vstup - IndexError

try:
    bouchneTo([0, 1, 2], 3)
except IndexError:                 # obsluha výjimky
    print 'To je mi překvapení!'

print 'Papuče!'

MojeChyba = "Moje malá chybička."

def neco(soubor):
    raise MojeChyba

soubor = open('data', 'r')         # předpokládáme, že existuje

try:
    neco(soubor)                   # vyhodí výjimku
finally:                           # obecně je ale dobré soubor
    soubor.close()                 #  zavřít ...

### Vybrané idiomy

while 1:
    try: radek = raw_input()       # načítá ze stdin
    except EOFError: break         # konec souboru i smyčky
    else: nějak zpracováváme radek

Nalezeno = "Položka nalezena"

def hledac(): vyhodí Nalezeno nebo prostě skončí

try: hledac()
except Found: Nalezena             # výjimka - nalezeno
else: Nenalezena                   # jinak - nenalezeno

try:
    Spustíme program
except:                            # všechny neošetřené výjimky
    import sys
    print 'Neošetřená výjimka', sys.exc_type, sys.exc_value

### Obsluha výjimek

try:
    neco()
except NameError:
    ...
except IndexError
    ...
except KeyError:
    ...
except (AttributeError, TypeError, SyntaxError):
    ...
else:
    ...

% cat vnortry.py

def fce2():
    print 1 + []           # vyhodí TypeError

def fce1():
    try:
        fce2()
    except TypeError:      # z pohledu fce2 “poslední” try
        print 'vnitřní'    # zkuste ještě znovu raise ...

try:
    fce1()
except TypeError:          # ... a skončíte tady
    print 'vnější'

% python vnortry.py

vnitřní

% cat finally.py

def vydel(x, y):
    return x / y                   # dělení nulou?

def test(y):
    try: print vydel(8, y)
    finally: print 'na závěr ...'

print 'test(2):'; test(2)
print 'test(0):'; test(0)          # vyhodí chybu

% python finally.py

test(2):
4
na závěr ...
test(0):
na závěr ... 

Traceback (most recent call last):
  File "C:\Python22\finally.py", line 9, in ?
    print 'test(0):'; test(0)          # vyhodí chybu
  File "C:\Python22\finally.py", line 5, in test
    try: print vydel(8, y)
  File "C:\Python22\finally.py", line 2, in vydel
    return x / y                   # dělení nulou?
ZeroDivisionError: integer division or modulo by zero 

### Věcičky

% cat ahojvyj.py

mojeVyjimka = 'Chyba'              # řetězec

def vyhazovac1():
    raise mojeVyjimka, "ahojte"    # předá "něco navíc"

def vyhazovac2():
    raise mojeVyjimka              # implicitní None

def zkousecka(fce):
    try:
        fce()                      # spustí fce a zachytí
    except mojeVyjimka, navic:     #  výjimku i "něco navíc"
        print 'dostali jsme:', navic 

% python

>>> from ahojvyj import *
>>> zkousecka(vyhazovac1)
dostali jsme: ahojte
>>> zkousecka(vyhazovac2)
dostali jsme: None

assert <podmínka>, <hodnota>       # hodnota není nutná

if __debug__:
    if not <podmínka>:
        raise AssertionError, <hodnota>

raise retezec, data                # + dodatečné informace 
raise retezec                      #  implicitně None

raise trida, instance              # except <třídaNeboPotomek>
raise instance                     # obdoba raise i.__class__, i

raise                              # opět. vyhodí akt. výjimku

raise trida                        # všechny obdobou raise i
raise trida, arg                   # = raise trida(arg) ...
raise trida, (arg1, arg2, ...)     # prostě arg. kontruktoru

% cat tridvyj.py

import sys

class Predek: pass
class Potomek(Predek): pass

def vyhazovac1():
    X = Predek()
    raise X

def vyhazovac2():
    X = Potomek()
    raise X

for fce in (vyhazovac1, vyhazovac2):
    try: fce()
    except Predek:
        # zachycuje instance třídy Predek a její potomky
        print 'Zachycena', sys.exc_type

% python tridvyj.py

Zachycena __main__.Predek
Zachycena __main__.Potomek

### Oblíbené problémy

>>> vyj1 = "něco"
>>> vyj2 = "něco"
>>> vyj1 == vyj2, vyj1 is vyj2
(1, 0)

>>> try:
...     raise vyj1
... except vyj1:
...     print 'zachyceno'
...
zachyceno

>>> try:
...     raise vyj1
... except vyj2:
...     print 'zachyceno'
...
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
něco

try: ...
except: ...

try: x = mujSlonvik[neco]                # prostě překlep
except: x = None

try: ...                                 # mojevyj1/2 není chyba
except (mojevyj1, mojevyj2): ...         # mojevyj3 už se šíří

### Shrnutí

### Cvičení