from IPython.core.display import HTML
HTML(open("custom.html", "r").read())
def f(x):
return 1 / x
def g(x):
return f(x - 1)
g(1)
If you read the long error message carefully (this is called a stack trace) you can see how the error was caused along the function calls.
In languages having no exception mechanism (C, Fortran, ...) programers indicate error situations either using a global error variable or by using special return values. The drawbacks of these approaches are:
In the situation above the divison by zero caused stopping program execution. Here comes "exception handling" to the rescue: The try
- except
statements allow us to catch exceptions of a given class and handle them apropriately:
try:
x = 1 / 0
except ZeroDivisionError as e:
print("oops, I got '%s'" % e)
print("I reached the end of the program")
In the code above all ZeroDivisionError
caused in the code block after try
are caught and the code block after except
is executed instead. In any case program execution continues after the try
- except
statements.
As you can see other exception classes are not caught in our code:
try:
x = "1" * "2"
except ZeroDivisionError as e:
print("oops, I got '%s'" % e)
print("I reached the end of the program")
To catch multiple exceptions we use the following syntax:
import random
try:
if random.random() >= 0.5:
x = "1" * "2"
else:
x = 1 / 0
except (ZeroDivisionError, TypeError) as e:
print("oops, I got '%s'" % e)
print("I reached the end of the program")
In some situations we want to add an extra handling but then let the error handling process as usual. For this we can "reraise" the exception:
The existing exceptions have an hierarchical order, see https://docs.python.org/3/library/exceptions.html#exception-hierarchy
So the "general" exception Exception
subsumes ZeroDivisonError
and TypeError
. Using except Exception
will catch both, and we can modify our excample like this:
import random
try:
if random.random() >= 0.5:
x = "1" * "2"
else:
x = 1 / 0
except Exception as e:
print("oops, I got '%s'" % e)
print("I reached the end of the program")
So: take some time for proper exception handling, only catch the exceptions you are aware of, so for example catch the VisaIOError
exception from pyvisa
if needed.
In case of nested functions an exception in an inner function will "bubble up". Either it is caught inbetween or the program execution will end. We can catch this exception on differnt levels, here we do this on the top level:
def f(x):
x = 1 / x
def g(x):
f(x)
def h(x):
g(0)
try:
h(0)
except ZeroDivisionError as e:
print("got '%s'" % e)
def f(x):
if x < 0:
raise ValueError("x is negative !")
f(-1)
"It's easier to ask forgiveness than it is to get permission" (https://en.wikiquote.org/wiki/Grace_Hopper#Quotes):
def is_proper_float(x):
try:
float(x)
return True
except ValueError:
return False
while True:
user_input = input("give me a real number: ")
if is_proper_float(user_input):
break
print("I told you to enter a real number !")
print("well done !")
the assert
statement raises an exception if the condition following the assert
is false. We typeically use this for sanity checks and to implement type checks:
import math
def root(x):
assert isinstance(x, int) or isinstance(x, float), "expected int or float, got %r" % x
assert x >= 0, "expected non-negative x"
return math.sqrt(x)
print(root("1"))