try/except are for interrupting normal program flow and continuing in surrounding contextExamples of exceptions resulting from programmer error (and therefore may not worth catching)
IndentationErrorSyntaxErrorNameErrorconvert example
DIGIT_MAP = {
'zero': '0',
'one': '1',
'two': '2',
'three': '3',
'four': '4',
'five': '5',
'six': '6',
'seven': '7',
'eight': '8',
'nine': '9'
}
def convert(s):
number = ''
for token in s:
number += DIGIT_MAP[token]
x = int(number)
return x
>>> from exceptional import convert
>>> convert("one three three seven".split())
#=> 1337
>>> convert("around two grillion".split())
#=> throws KeyError
convert example (v2.0)
import sys
DIGIT_MAP = {
'zero': '0',
'one': '1',
'two': '2',
'three': '3',
'four': '4',
'five': '5',
'six': '6',
'seven': '7',
'eight': '8',
'nine': '9'
}
def convert(s):
try:
number = ''
for token in s:
number += DIGIT_MAP[token]
return int(number)
except (KeyError, TypeError) as e:
# `!r` results in using repl representation of value in string
# stderr === standard error
print(f"Conversion error: {e!r}", file=sys.stderr)
return -1
pass### BAD
def do_something(x):
try:
x += "meow"
except TypeError:
return x
### GOOD
def do_something(x):
try:
x += "meow"
except TypeError:
pass
return xtry...finallyBasic syntax:
try:
# try-block
finally:
# executed no matter how the try-block terminatesfinallyNot-Exception-safe
import os
def make_at(path, dir_name):
original_path = os.getcwd()
os.chdir(path)
os.mkdir(dir_name)
os.chdir(original_path)Cleans up from Exceptions
import os
import sys
def make_at(path, dir_name):
original_path = os.getcwd()
os.chdir(path)
try:
os.mkdir(dir_name)
finally:
os.chdir(original_path)Extended with added except block
import os
import sys
def make_at(path, dir_name):
original_path = os.getcwd()
os.chdir(path)
try:
os.mkdir(dir_name)
except OSError as e:
print(e, file=sys.stderr)
raise
finally: ###### NOTE: this block will still run, even if exception is raised
os.chdir(original_path)β―οΈ Moment of Zen β―οΈ "Errors should never pass silently, unless explicitly silenced" Errors are like bells And if we make them silent They are of no use
π‘ IMPORTANT π‘ instead of returning error codes, just raise an exception π
convert example (v3.0)
import sys
from math import log
DIGIT_MAP = {
'zero': '0',
'one': '1',
'two': '2',
'three': '3',
'four': '4',
'five': '5',
'six': '6',
'seven': '7',
'eight': '8',
'nine': '9'
}
def convert(s):
try:
number = ''
for token in s:
number += DIGIT_MAP[token]
return int(number)
except (KeyError, TypeError) as e:
# `!r` results in using repl representation of value in string
# stderr === standard error
print(f"Conversion error: {e!r}", file=sys.stderr)
raise
def string_log(s):
v = convert(s)
return log(v)
Whenever possible and sensible, use Standard Exception Types
ValueError for arguments of the right type but with invalid valueraise ValueError() to raise new ValueErrorsqrt exampleimport sys
def sqrt(x):
"""Compute square roots using the method of Heron of Alexandria.
Args:
x: The number for which the square root is to be computed.
Returns:
The square root of x.
"""
guess = x
i = 0
# catching `ZeroDivisionError` and raising as `ValueError`
try:
while guess * guess != x and i < 20:
guess = (guess + x / guess) / 2.0
i += 1
except ZeroDivisionError:
# this is wasteful since we KNOW that the function will fail if x is a negative number
raise ValueError()
return guess
def main():
try:
print(sqrt(9))
print(sqrt(2))
print(sqrt(-1)) # raises ZeroDivisionError
print("This is never printed.")
except ZeroDivisionError:
print("Cannot compute square root of a negative number.")
print("Program execution continues normally here.")
if __name__ == '__main__':
main()
import sys
def sqrt(x):
"""Compute square roots using the method of Heron of Alexandria.
Args:
x: The number for which the square root is to be computed.
Returns:
The square root of x.
Raises:
ValueError: If x is negative.
"""
if x < 0:
raise ValueError(f"Cannot compute square root of negative number {x}")
guess = x
i = 0
while guess * guess != x and i < 20:
guess = (guess + x / guess) / 2.0
i += 1
return guess
def main():
try:
print(sqrt(9))
print(sqrt(2))
print(sqrt(-1))
print("This is never printed.")
except ValueError as e:
print(e, file=sys.stderr)
print("Program execution continues normally here.")
if __name__ == '__main__':
main()