# Hibák és azok kezelése

:::tip TL;DR Tartalom

- [Hibák általánosságban](#hibák-általánosságban) -
  Objektumok, példák
- [Hibakezelés](#hibakezelés)
  - [Saját hiba osztályok](#saját-hiba-osztályok) - Ugyanolyan
    osztály
  - [try ... catch ...](#try--catch-) - Dobunk és elkapunk hibát
  - [else](#else) - Semmi hiba nem volt, csinálj valamit
  - [raise](#raise) - Hibával dobálózás
  - [finally](#finally) - Még a returnt is felülírjuk

:::tip

:::info Extra feladatok

_Ezek nem kötelező feladatok, csak megoldásuk közben könyebb
megtanulni a dolgokat_

- Készíts egy saját hiba osztályt, melyben letárolsz
  egy számot és híváskor kiírja azt.
  (Tipp: `__init__`, `__str__`)
- Imént definiált hibát kapd el, irasd ki és ne hagyd
  miatta leállni a programot.

:::info

## Hibák általánosságban

Python, mint magasszintű nyelv hibák dobására és azok
kezelésére is képes.
Ezek olyan objektumok, melyekkel a program futásának
vezérlési szerkezetét tudjuk megszakítani, majd valahol
lekezelni őket.

Alapvetően ha nem kerülnek lekezelésre, akkor a futás megáll
és a hibát kiírja nekünk az interpeter.  
A leggyakoribb hiba, amivel a Python tanulása közben fogsz
találkozni, az a SyntaxError.

```python
>>> while True print('Hello world')
  File "<stdin>", line 1
    while True print('Hello world')
                   ^
SyntaxError: invalid syntax
```

Valamennyire próbál neked segíteni a fordító mikor ilyen
keletkezik.

Még egy pár hiba:

```python
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly
```

## Hibakezelés

### Saját hiba osztályok

Tudunk készíteni saját hibákat.  
Ehhez csak egy osztályt kell készítenünk.

```python
class ForgovillaHiba(Exception): # Leszármazik az Exceptionből
    """Valami baj van a forgóvillával"""
    pass # sad SCH noises
```

### try ... catch ...

`try` és `except` kulcsszavakkal eltudjuk kapni a különböző
hibáinkat.

```python
>>> while True:
...     try:
...         x = int(input("Adj meg egy számot: "))
...         break
...     except ValueError:
...         print("Ez nem egy szám...")
...
```

A `try`-on belüli részen ha keletkezik bármilyen hiba, akkor
azonnal tovább dobja az `except`-hez.
Itt definiálhatjuk, hogy milyen típusú hibát szeretnénk
elkapni.

Akár többet is elkaphatunk egyben:

```python
... except (RuntimeError, TypeError, NameError):
...     pass
```

Az `except` részben definiált osztályok akkor kapják el
az adott hibát, ha kompatibilisek a dobott hibával.

Tanulmányozd, hogy mit dob ez esetben a kód:

```python
class B(Exception):
    pass

class C(B):
    pass

class D(C):
    pass

for osztaly in [B, C, D]:
    try:
        raise osztaly()
    except D:
        print("D")
    except C:
        print("C")
    except B:
        print("B")
```

Különböző dobott hibákat akár le is menthetjük
egy változóba, majd annak tartalmával dolgozhatunk.

```python
import sys

try:
    f = open('fajl.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("Nem sikerült intbe konvertálni.")
except: # Minden más
    print("Váratlan hiba:", sys.exc_info()[0])
    raise
```

### else

Egy `try`, `catch` blokk legvégére tehetünk egy `else`-t,
hogy lefuttasunk valamit ha nem történt semmi hiba.

### raise

Mi is tudunk hibákat dobni a `raise`
kulcsszó segítségével.

```python
>>> raise NameError('HiThere')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: HiThere
```

```python
>>> try:
...     raise NameError('HiThere')
... except NameError:
...     print('Egy hiba történt!')
...     raise
...
'Egy hiba történt!'
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
NameError: HiThere
```

### finally

Végül pedig a `try` lefutása után tudunk definiálni még
lépéseket.
Az itt definiált dolgok mindenképp lefognak futni, ha volt,
ha nem volt hiba.

```python
>>> def fv():
...     try:
...         return True
...     finally:
...         return False
...
>>> fv()
False
```