<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Exceptions
An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.
You've already seen some exceptions in the Debugging lesson.
* 
Many programs want to know about exceptions when they occur. For example, if the input to a program is a file path. If the user inputs an invalid or non-existent path, the program generates an exception. It may be desired to provide a response to the user in this case.
It may also be that programs will generate exceptions. This is a way of indicating that there is an error in the inputs provided. In general, this is the preferred style for dealing with invalid inputs or states inside a python function rather than having an error return.
Catching Exceptions
Python provides a way to detect when an exception occurs. This is done by the use of a block of code surrounded by a "try" and "except" statement.
Step1:  Why didn't we catch this SyntaxError?
Step3:  What do you do when you get an exception?
First, you can feel relieved that you caught a problematic element of your software! Yes, relieved. Silent fails are much worse. (Again, another plug for testing.)
Generating Exceptions
Why generate exceptions? (Don't I have enough unintentional errors?)
<ASSISTANT_TASK:>
Python Code:
def divide(numerator, denominator):
    result = numerator/denominator
    print("result = %f" % result)
divide(1.0, 0)
def divide1(numerator, denominator):
    try:
        GARBAGE
        result = numerator/denominator
        print("result = %f" % result)
    except (ZeroDivisionError, NameError) as err:
        import pdb; pdb.set_trace()
        print("You can't divide by 0! or use GARBAGE.")
divide1(1.0, 'a')
print(err)
divide1(1.0, 2)
divide1("x", 2)
def divide2(numerator, denominator):
    try:
        result = numerator / denominator
        print("result = %f" % result)
    except (ZeroDivisionError, TypeError) as err:
        print("Got an exception: %s" % err)
divide2(1, "X")
#divide2("x, 2)
Explanation: Exceptions
An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.
You've already seen some exceptions in the Debugging lesson.
* 
Many programs want to know about exceptions when they occur. For example, if the input to a program is a file path. If the user inputs an invalid or non-existent path, the program generates an exception. It may be desired to provide a response to the user in this case.
It may also be that programs will generate exceptions. This is a way of indicating that there is an error in the inputs provided. In general, this is the preferred style for dealing with invalid inputs or states inside a python function rather than having an error return.
Catching Exceptions
Python provides a way to detect when an exception occurs. This is done by the use of a block of code surrounded by a "try" and "except" statement.
End of explanation
# Handle division by 0 by using a small number
SMALL_NUMBER = 1e-3
def divide3(numerator, denominator):
    try:
        result = numerator/denominator
    except ZeroDivisionError:
        result = numerator/SMALL_NUMBER
        print("result = %f" % result)
    except Exception as err:
        print("Different error than division by zero:", err)
divide3(1,0)
divide3("1",0)
Explanation: Why didn't we catch this SyntaxError?
End of explanation
import pandas as pd
def validateDF(df):
    "
    :param pd.DataFrame df: should have a column named "hours"
    
    if not "hours" in df.columns:
        raise ValueError("DataFrame should have a column named 'hours'.")
df = pd.DataFrame({'hours': range(10) })
validateDF(df)
class SeattleCrimeError(Exception):
    pass
b = False
if not b:
    raise SeattleCrimeError("There's been a crime!")
Explanation: What do you do when you get an exception?
First, you can feel relieved that you caught a problematic element of your software! Yes, relieved. Silent fails are much worse. (Again, another plug for testing.)
Generating Exceptions
Why generate exceptions? (Don't I have enough unintentional errors?)
End of explanation
<END_TASK>