Sebuah exception bisa menyebabkan exception lainnya. Python hanya support satu exception per satu waktu, untuk mengatasinya Python menyediakan chaining exception.
Dengan Chaining, kita bisa asosiasikan satu exception dengan exception lainnya.
Chaining ada dua macam, explicit dan implicit.
Implicit Chaining
Exception kedua terjadi saat memproses exception pertama, ditangani oleh Python secara otomatis.
Berikut demo program untuk implicit chaining, kita gunakan program sebelumnya dengan modifikasi menambahkan 2 bug.
import math
import sys
class TriangleError (Exception):
def __init__ (self, text, sides):
super().__init__(text)
self._sides = tuple(sides)
@property
def sides(self):
return self._sides
def __str__(self):
return "'{}' for sides {}".format(self.args[0], self._sides)
def __repr__(self):
return "TriangleError({!r}, {!r})".format(self.args[0], self._sides)
def luas_segitiga(a, b, c):
sides = sorted((a, b, c))
if sides[2] > sides [0] + sides [1]:
raise TriangleError("Segitiga Error", sides)
s = (a + b + c) / 2
l = math.sqrt(s * (s-a) * (s-b) * (s-c))
return l
def main():
try:
a = luas_segitiga(3, 4, 10)
print(a)
except TriangleError as e:
print(e, file=sys.stdin)
PS F:\Project\pyErrHandling> python
Python 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:43:08) [MSC v.1926 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from heron import *
>>> main()
Traceback (most recent call last):
File "F:\Project\pyErrHandling\heron.py", line 31, in main
a = luas_segitiga(3, 4, 10)
File "F:\Project\pyErrHandling\heron.py", line 23, in luas_segitiga
raise TriangleError("Segitiga Error", sides)
heron.TriangleError: 'Segitiga Error' for sides (3, 4, 10)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "F:\Project\pyErrHandling\heron.py", line 34, in main
print(e, file=sys.stdin)
io.UnsupportedOperation: not writable
Perhatikan log diatas, terdapat error log “During handling of the above exception, another exception occured”.
Implicit chaining menyimpan exception pertama pada __context__ attribute. Lihat code dibawah yang untuk menunjukan exception terdapat pada __context__ attribute.
import math
import sys
import io
class TriangleError (Exception):
def __init__ (self, text, sides):
super().__init__(text)
self._sides = tuple(sides)
@property
def sides(self):
return self._sides
def __str__(self):
return "'{}' for sides {}".format(self.args[0], self._sides)
def __repr__(self):
return "TriangleError({!r}, {!r})".format(self.args[0], self._sides)
def luas_segitiga(a, b, c):
sides = sorted((a, b, c))
if sides[2] > sides [0] + sides [1]:
raise TriangleError("Segitiga Error", sides)
s = (a + b + c) / 2
l = math.sqrt(s * (s-a) * (s-b) * (s-c))
return l
def main():
try:
a = luas_segitiga(3, 4, 10)
print(a)
except TriangleError as e:
try:
print(e, file=sys.stdin)
except io.UnsupportedOperation as f:
print(e)
print(f)
print(f.__context__ is e)
>>> main()
'Segitiga Error' for sides (3, 4, 10)
not writable
True
Explicit Chaining
Secara eksplisit ditulis dalam program untuk meresponse terhadap exception yang terjadi saat memprose exception pertama.
Berikut program sederhana untuk menghitung kemiringan. Untuk chaining secara eksplisit, digunakan keyword from.
import math
class InclinationErr(Exception):
pass
def inclination(dx, dy):
try:
return math.degrees(math.atan(dy/dx))
except ZeroDivisionError as e:
raise InclinationErr("Tidak ada kemiringan") from e
>>> from inclination import *
>>> inclination(0, 2)
Traceback (most recent call last):
File "F:\Project\pyErrHandling\inclination.py", line 8, in inclination
return math.degrees(math.atan(dy/dx))
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "F:\Project\pyErrHandling\inclination.py", line 10, in inclination
raise InclinationErr("Tidak ada kemiringan") from e
inclination.InclinationErr: Tidak ada kemiringan
>>>
log diatas menunjukan exception message berbeda dengan implicit chaining, yaitu “The above exception was the direct cause of the following exception:”
Explicit chaining menyimpan exception pertama pada __cause__ attribute.
>>> try:
... inclination(0,5)
... except InclinationErr as e:
... print(e)
... print(e.__cause__)
...
Tidak ada kemiringan
division by zero