Raising errors yourself
Your own code can raise an exception too, with the raise statement. Causing errors on purpose may sound odd, but it's the clearest way for a function to say "I can't do this with these arguments". A function that only prints an error message is easy to miss, especially when its result goes on to other code, and one that returns a special value, such as -1, risks having that value used as if it were a real result. An exception can't be missed: it stops the program unless the caller handles it.
def hours_to_minutes(hours):
if hours < 0:
raise ValueError(f"hours can't be negative: {hours}")
return hours * 60
print(hours_to_minutes(2))
print(hours_to_minutes(-3))
120Traceback (most recent call last):
File "main.py", line 8, in <module>
print(hours_to_minutes(-3))
~~~~~~~~~~~~~~~~^^^^
File "main.py", line 3, in hours_to_minutes
raise ValueError(f"hours can't be negative: {hours}")
ValueError: hours can't be negative: -3After raise comes the exception: its kind, with a message in parentheses. ValueError is the usual choice for a value that isn't acceptable, and TypeError for a value of the wrong type. The message is shown in the traceback, so make it say what was wrong.
Catching your own exceptions
The caller handles a raised exception like any other. With as, the except line also gives the exception a name, and printing it prints its message:
def booking(guests, nights):
if guests < 1 or guests > 6:
raise ValueError(f"a room takes 1 to 6 guests, not {guests}")
if nights < 1:
raise ValueError(f"a stay is at least one night, not {nights}")
return (guests, nights)
try:
print("Booked:", booking(2, 3))
print("Booked:", booking(9, 1))
except ValueError as error:
print("Can't book:", error)
Booked: (2, 3)
Can't book: a room takes 1 to 6 guests, not 9This is a good division of work. The function checks its arguments and raises an exception when they're wrong; it doesn't need to know who called it or how to talk to the user. The code that talks to the user catches the exception and decides what to say.