Menu iconMenu iconPython Programming Unlocked for Beginners
Python Programming Unlocked for Beginners

Chapter 9: Error Handling and Exceptions

9.2: Handling Exceptions with try and except

Python is an incredibly versatile programming language that offers a wide range of tools and features to developers. One such feature is the ability to handle exceptions using the try and except statements. These statements allow developers to monitor code execution and provide a means of dealing with exceptions that may arise during runtime. 

When a block of code is enclosed within a try statement, Python executes the code, monitoring it for any exceptions that might occur. This means that even if an exception is raised, the program can continue to execute without crashing or causing other issues. Instead, the program execution jumps to the appropriate except block, which is designed to handle the specific exception or tuple of exceptions that was raised. 

It is important to note that the try statement should be followed by one or more except blocks. These blocks are designed to handle the specific exceptions that may arise during runtime. Additionally, you can also use an optional else block to specify code that will be executed if no exceptions occur. This is useful for cases where you want to perform additional actions if the code runs without issue.

Finally, there is the finally block. This block is used to specify code that will be executed regardless of whether an exception occurred or not. This is useful for cases where you need to clean up resources or perform other actions that are required regardless of the outcome of the program execution. 

In sumary, the try and except statements are valuable tools for any Python developer. By using these statements, you can handle exceptions in a way that allows your program to continue executing even if errors occur. Additionally, the else and finally blocks provide additional functionality that can be used to make your code more robust and reliable.

Here's the general syntax for a try-except statement:

try:
    # code that might raise an exception
except ExceptionType1:
    # code to handle exception of type ExceptionType1
except (ExceptionType2, ExceptionType3):
    # code to handle exception of type ExceptionType2 or ExceptionType3
else:
    # code to be executed if no exception was raised
finally:
    # code that will always be executed, regardless of exceptions

An example of using the try and except statements to handle exceptions:

try:
    numerator = 10
    denominator = 0
    result = numerator / denominator
except ZeroDivisionError:
    print("Cannot divide by zero")
except Exception as e:
    print("An unknown error occurred:", e)
else:
    print("The division was successful:", result)
finally:
    print("Thank you for using our division calculator")

In this example, we first try to perform the division operation. If a ZeroDivisionError occurs, we print an informative message. If any other exception occurs, we catch it using the Exception class, which is a base class for all built-in exceptions, and print an unknown error message. If no exception occurs, we print the result of the division. Finally, we print a message thanking the user for using our division calculator, regardless of whether an exception occurred or not.

When using try and except, it's important to handle the exceptions that you expect to occur and allow the others to be propagated up the call stack. This is because catching too many exceptions or defining a broad exception class like Exception can lead to difficulty identifying and resolving issues in the code. Moreover, it can even hide legitimate errors that should be addressed.

For instance, when catching a broad exception class like Exception, it's possible that we may miss a specific exception that was not anticipated or that we don't know how to handle. In such a case, the exception will be caught and processed by the general exception handler, which may not be able to handle the specific exception adequately. As a result, the error may be hidden or even worse, the code may continue to run with an unexpected behavior.

On the other hand, when we catch only the exceptions that we expect to occur, we can handle them specifically and provide better error messages to the users. This can help to improve the quality of the code and make it easier to maintain and debug. Additionally, it can make the code more robust against unexpected changes in the environment or input data.

Therefore, it's recommended to be cautious when defining exception handlers and only catch the exceptions that we can handle appropriately. This can help to make the code more reliable and easier to maintain in the long run.

Exercise 9.2.1: Safe File Reading

Write a program that tries to read a file given by the user and prints the contents of the file. If the file is not found or cannot be read, display an error message.

Instructions:

  1. Prompt the user for a filename.
  2. Use a try-except block to open the file and read its content.
  3. If a FileNotFoundError occurs, print an error message.
  4. Otherwise, print the contents of the file.
  5. Close the file.

Solution:

filename = input("Enter the filename: ")

try:
    with open(filename, "r") as file:
        content = file.read()
except FileNotFoundError:
    print(f"Error: The file '{filename}' does not exist or could not be found.")
else:
    print("File contents:")
    print(content)

Output:

Enter the filename: sample.txt
File contents:
This is a sample text file.

Exercise 9.2.2: Safe Division

Write a program that takes two numbers as input and performs division. If a division by zero occurs, display an error message.

Instructions:

  1. Prompt the user for two numbers.
  2. Use a try-except block to perform the division.
  3. If a ZeroDivisionError occurs, print an error message.
  4. Otherwise, print the result of the division.

Solution:

numerator = float(input("Enter the numerator: "))
denominator = float(input("Enter the denominator: "))

try:
    result = numerator / denominator
except ZeroDivisionError:
    print("Error: Division by zero is not allowed.")
else:
    print(f"The result is {result}.")

Output:

Enter the numerator: 10
Enter the denominator: 0
Error: Division by zero is not allowed.

Exercise 9.2.3: Safe List Indexing

Write a program that tries to access an element in a list by its index given by the user. If an IndexError occurs, display an error message.

Instructions:

  1. Create a list with some elements.
  2. Prompt the user for an index.
  3. Use a try-except block to access the element at the given index.
  4. If an IndexError occurs, print an error message.
  5. Otherwise, print the accessed element.

Solution:

my_list = [10, 20, 30, 40, 50]
index = int(input("Enter the index of the element to retrieve: "))

try:
    element = my_list[index]
except IndexError:
    print(f"Error: The index '{index}' is out of range.")
else:
    print(f"The element at index {index} is {element}.")

Output:

Enter the index of the element to retrieve: 7
Error: The index '7' is out of range.

9.2: Handling Exceptions with try and except

Python is an incredibly versatile programming language that offers a wide range of tools and features to developers. One such feature is the ability to handle exceptions using the try and except statements. These statements allow developers to monitor code execution and provide a means of dealing with exceptions that may arise during runtime. 

When a block of code is enclosed within a try statement, Python executes the code, monitoring it for any exceptions that might occur. This means that even if an exception is raised, the program can continue to execute without crashing or causing other issues. Instead, the program execution jumps to the appropriate except block, which is designed to handle the specific exception or tuple of exceptions that was raised. 

It is important to note that the try statement should be followed by one or more except blocks. These blocks are designed to handle the specific exceptions that may arise during runtime. Additionally, you can also use an optional else block to specify code that will be executed if no exceptions occur. This is useful for cases where you want to perform additional actions if the code runs without issue.

Finally, there is the finally block. This block is used to specify code that will be executed regardless of whether an exception occurred or not. This is useful for cases where you need to clean up resources or perform other actions that are required regardless of the outcome of the program execution. 

In sumary, the try and except statements are valuable tools for any Python developer. By using these statements, you can handle exceptions in a way that allows your program to continue executing even if errors occur. Additionally, the else and finally blocks provide additional functionality that can be used to make your code more robust and reliable.

Here's the general syntax for a try-except statement:

try:
    # code that might raise an exception
except ExceptionType1:
    # code to handle exception of type ExceptionType1
except (ExceptionType2, ExceptionType3):
    # code to handle exception of type ExceptionType2 or ExceptionType3
else:
    # code to be executed if no exception was raised
finally:
    # code that will always be executed, regardless of exceptions

An example of using the try and except statements to handle exceptions:

try:
    numerator = 10
    denominator = 0
    result = numerator / denominator
except ZeroDivisionError:
    print("Cannot divide by zero")
except Exception as e:
    print("An unknown error occurred:", e)
else:
    print("The division was successful:", result)
finally:
    print("Thank you for using our division calculator")

In this example, we first try to perform the division operation. If a ZeroDivisionError occurs, we print an informative message. If any other exception occurs, we catch it using the Exception class, which is a base class for all built-in exceptions, and print an unknown error message. If no exception occurs, we print the result of the division. Finally, we print a message thanking the user for using our division calculator, regardless of whether an exception occurred or not.

When using try and except, it's important to handle the exceptions that you expect to occur and allow the others to be propagated up the call stack. This is because catching too many exceptions or defining a broad exception class like Exception can lead to difficulty identifying and resolving issues in the code. Moreover, it can even hide legitimate errors that should be addressed.

For instance, when catching a broad exception class like Exception, it's possible that we may miss a specific exception that was not anticipated or that we don't know how to handle. In such a case, the exception will be caught and processed by the general exception handler, which may not be able to handle the specific exception adequately. As a result, the error may be hidden or even worse, the code may continue to run with an unexpected behavior.

On the other hand, when we catch only the exceptions that we expect to occur, we can handle them specifically and provide better error messages to the users. This can help to improve the quality of the code and make it easier to maintain and debug. Additionally, it can make the code more robust against unexpected changes in the environment or input data.

Therefore, it's recommended to be cautious when defining exception handlers and only catch the exceptions that we can handle appropriately. This can help to make the code more reliable and easier to maintain in the long run.

Exercise 9.2.1: Safe File Reading

Write a program that tries to read a file given by the user and prints the contents of the file. If the file is not found or cannot be read, display an error message.

Instructions:

  1. Prompt the user for a filename.
  2. Use a try-except block to open the file and read its content.
  3. If a FileNotFoundError occurs, print an error message.
  4. Otherwise, print the contents of the file.
  5. Close the file.

Solution:

filename = input("Enter the filename: ")

try:
    with open(filename, "r") as file:
        content = file.read()
except FileNotFoundError:
    print(f"Error: The file '{filename}' does not exist or could not be found.")
else:
    print("File contents:")
    print(content)

Output:

Enter the filename: sample.txt
File contents:
This is a sample text file.

Exercise 9.2.2: Safe Division

Write a program that takes two numbers as input and performs division. If a division by zero occurs, display an error message.

Instructions:

  1. Prompt the user for two numbers.
  2. Use a try-except block to perform the division.
  3. If a ZeroDivisionError occurs, print an error message.
  4. Otherwise, print the result of the division.

Solution:

numerator = float(input("Enter the numerator: "))
denominator = float(input("Enter the denominator: "))

try:
    result = numerator / denominator
except ZeroDivisionError:
    print("Error: Division by zero is not allowed.")
else:
    print(f"The result is {result}.")

Output:

Enter the numerator: 10
Enter the denominator: 0
Error: Division by zero is not allowed.

Exercise 9.2.3: Safe List Indexing

Write a program that tries to access an element in a list by its index given by the user. If an IndexError occurs, display an error message.

Instructions:

  1. Create a list with some elements.
  2. Prompt the user for an index.
  3. Use a try-except block to access the element at the given index.
  4. If an IndexError occurs, print an error message.
  5. Otherwise, print the accessed element.

Solution:

my_list = [10, 20, 30, 40, 50]
index = int(input("Enter the index of the element to retrieve: "))

try:
    element = my_list[index]
except IndexError:
    print(f"Error: The index '{index}' is out of range.")
else:
    print(f"The element at index {index} is {element}.")

Output:

Enter the index of the element to retrieve: 7
Error: The index '7' is out of range.

9.2: Handling Exceptions with try and except

Python is an incredibly versatile programming language that offers a wide range of tools and features to developers. One such feature is the ability to handle exceptions using the try and except statements. These statements allow developers to monitor code execution and provide a means of dealing with exceptions that may arise during runtime. 

When a block of code is enclosed within a try statement, Python executes the code, monitoring it for any exceptions that might occur. This means that even if an exception is raised, the program can continue to execute without crashing or causing other issues. Instead, the program execution jumps to the appropriate except block, which is designed to handle the specific exception or tuple of exceptions that was raised. 

It is important to note that the try statement should be followed by one or more except blocks. These blocks are designed to handle the specific exceptions that may arise during runtime. Additionally, you can also use an optional else block to specify code that will be executed if no exceptions occur. This is useful for cases where you want to perform additional actions if the code runs without issue.

Finally, there is the finally block. This block is used to specify code that will be executed regardless of whether an exception occurred or not. This is useful for cases where you need to clean up resources or perform other actions that are required regardless of the outcome of the program execution. 

In sumary, the try and except statements are valuable tools for any Python developer. By using these statements, you can handle exceptions in a way that allows your program to continue executing even if errors occur. Additionally, the else and finally blocks provide additional functionality that can be used to make your code more robust and reliable.

Here's the general syntax for a try-except statement:

try:
    # code that might raise an exception
except ExceptionType1:
    # code to handle exception of type ExceptionType1
except (ExceptionType2, ExceptionType3):
    # code to handle exception of type ExceptionType2 or ExceptionType3
else:
    # code to be executed if no exception was raised
finally:
    # code that will always be executed, regardless of exceptions

An example of using the try and except statements to handle exceptions:

try:
    numerator = 10
    denominator = 0
    result = numerator / denominator
except ZeroDivisionError:
    print("Cannot divide by zero")
except Exception as e:
    print("An unknown error occurred:", e)
else:
    print("The division was successful:", result)
finally:
    print("Thank you for using our division calculator")

In this example, we first try to perform the division operation. If a ZeroDivisionError occurs, we print an informative message. If any other exception occurs, we catch it using the Exception class, which is a base class for all built-in exceptions, and print an unknown error message. If no exception occurs, we print the result of the division. Finally, we print a message thanking the user for using our division calculator, regardless of whether an exception occurred or not.

When using try and except, it's important to handle the exceptions that you expect to occur and allow the others to be propagated up the call stack. This is because catching too many exceptions or defining a broad exception class like Exception can lead to difficulty identifying and resolving issues in the code. Moreover, it can even hide legitimate errors that should be addressed.

For instance, when catching a broad exception class like Exception, it's possible that we may miss a specific exception that was not anticipated or that we don't know how to handle. In such a case, the exception will be caught and processed by the general exception handler, which may not be able to handle the specific exception adequately. As a result, the error may be hidden or even worse, the code may continue to run with an unexpected behavior.

On the other hand, when we catch only the exceptions that we expect to occur, we can handle them specifically and provide better error messages to the users. This can help to improve the quality of the code and make it easier to maintain and debug. Additionally, it can make the code more robust against unexpected changes in the environment or input data.

Therefore, it's recommended to be cautious when defining exception handlers and only catch the exceptions that we can handle appropriately. This can help to make the code more reliable and easier to maintain in the long run.

Exercise 9.2.1: Safe File Reading

Write a program that tries to read a file given by the user and prints the contents of the file. If the file is not found or cannot be read, display an error message.

Instructions:

  1. Prompt the user for a filename.
  2. Use a try-except block to open the file and read its content.
  3. If a FileNotFoundError occurs, print an error message.
  4. Otherwise, print the contents of the file.
  5. Close the file.

Solution:

filename = input("Enter the filename: ")

try:
    with open(filename, "r") as file:
        content = file.read()
except FileNotFoundError:
    print(f"Error: The file '{filename}' does not exist or could not be found.")
else:
    print("File contents:")
    print(content)

Output:

Enter the filename: sample.txt
File contents:
This is a sample text file.

Exercise 9.2.2: Safe Division

Write a program that takes two numbers as input and performs division. If a division by zero occurs, display an error message.

Instructions:

  1. Prompt the user for two numbers.
  2. Use a try-except block to perform the division.
  3. If a ZeroDivisionError occurs, print an error message.
  4. Otherwise, print the result of the division.

Solution:

numerator = float(input("Enter the numerator: "))
denominator = float(input("Enter the denominator: "))

try:
    result = numerator / denominator
except ZeroDivisionError:
    print("Error: Division by zero is not allowed.")
else:
    print(f"The result is {result}.")

Output:

Enter the numerator: 10
Enter the denominator: 0
Error: Division by zero is not allowed.

Exercise 9.2.3: Safe List Indexing

Write a program that tries to access an element in a list by its index given by the user. If an IndexError occurs, display an error message.

Instructions:

  1. Create a list with some elements.
  2. Prompt the user for an index.
  3. Use a try-except block to access the element at the given index.
  4. If an IndexError occurs, print an error message.
  5. Otherwise, print the accessed element.

Solution:

my_list = [10, 20, 30, 40, 50]
index = int(input("Enter the index of the element to retrieve: "))

try:
    element = my_list[index]
except IndexError:
    print(f"Error: The index '{index}' is out of range.")
else:
    print(f"The element at index {index} is {element}.")

Output:

Enter the index of the element to retrieve: 7
Error: The index '7' is out of range.

9.2: Handling Exceptions with try and except

Python is an incredibly versatile programming language that offers a wide range of tools and features to developers. One such feature is the ability to handle exceptions using the try and except statements. These statements allow developers to monitor code execution and provide a means of dealing with exceptions that may arise during runtime. 

When a block of code is enclosed within a try statement, Python executes the code, monitoring it for any exceptions that might occur. This means that even if an exception is raised, the program can continue to execute without crashing or causing other issues. Instead, the program execution jumps to the appropriate except block, which is designed to handle the specific exception or tuple of exceptions that was raised. 

It is important to note that the try statement should be followed by one or more except blocks. These blocks are designed to handle the specific exceptions that may arise during runtime. Additionally, you can also use an optional else block to specify code that will be executed if no exceptions occur. This is useful for cases where you want to perform additional actions if the code runs without issue.

Finally, there is the finally block. This block is used to specify code that will be executed regardless of whether an exception occurred or not. This is useful for cases where you need to clean up resources or perform other actions that are required regardless of the outcome of the program execution. 

In sumary, the try and except statements are valuable tools for any Python developer. By using these statements, you can handle exceptions in a way that allows your program to continue executing even if errors occur. Additionally, the else and finally blocks provide additional functionality that can be used to make your code more robust and reliable.

Here's the general syntax for a try-except statement:

try:
    # code that might raise an exception
except ExceptionType1:
    # code to handle exception of type ExceptionType1
except (ExceptionType2, ExceptionType3):
    # code to handle exception of type ExceptionType2 or ExceptionType3
else:
    # code to be executed if no exception was raised
finally:
    # code that will always be executed, regardless of exceptions

An example of using the try and except statements to handle exceptions:

try:
    numerator = 10
    denominator = 0
    result = numerator / denominator
except ZeroDivisionError:
    print("Cannot divide by zero")
except Exception as e:
    print("An unknown error occurred:", e)
else:
    print("The division was successful:", result)
finally:
    print("Thank you for using our division calculator")

In this example, we first try to perform the division operation. If a ZeroDivisionError occurs, we print an informative message. If any other exception occurs, we catch it using the Exception class, which is a base class for all built-in exceptions, and print an unknown error message. If no exception occurs, we print the result of the division. Finally, we print a message thanking the user for using our division calculator, regardless of whether an exception occurred or not.

When using try and except, it's important to handle the exceptions that you expect to occur and allow the others to be propagated up the call stack. This is because catching too many exceptions or defining a broad exception class like Exception can lead to difficulty identifying and resolving issues in the code. Moreover, it can even hide legitimate errors that should be addressed.

For instance, when catching a broad exception class like Exception, it's possible that we may miss a specific exception that was not anticipated or that we don't know how to handle. In such a case, the exception will be caught and processed by the general exception handler, which may not be able to handle the specific exception adequately. As a result, the error may be hidden or even worse, the code may continue to run with an unexpected behavior.

On the other hand, when we catch only the exceptions that we expect to occur, we can handle them specifically and provide better error messages to the users. This can help to improve the quality of the code and make it easier to maintain and debug. Additionally, it can make the code more robust against unexpected changes in the environment or input data.

Therefore, it's recommended to be cautious when defining exception handlers and only catch the exceptions that we can handle appropriately. This can help to make the code more reliable and easier to maintain in the long run.

Exercise 9.2.1: Safe File Reading

Write a program that tries to read a file given by the user and prints the contents of the file. If the file is not found or cannot be read, display an error message.

Instructions:

  1. Prompt the user for a filename.
  2. Use a try-except block to open the file and read its content.
  3. If a FileNotFoundError occurs, print an error message.
  4. Otherwise, print the contents of the file.
  5. Close the file.

Solution:

filename = input("Enter the filename: ")

try:
    with open(filename, "r") as file:
        content = file.read()
except FileNotFoundError:
    print(f"Error: The file '{filename}' does not exist or could not be found.")
else:
    print("File contents:")
    print(content)

Output:

Enter the filename: sample.txt
File contents:
This is a sample text file.

Exercise 9.2.2: Safe Division

Write a program that takes two numbers as input and performs division. If a division by zero occurs, display an error message.

Instructions:

  1. Prompt the user for two numbers.
  2. Use a try-except block to perform the division.
  3. If a ZeroDivisionError occurs, print an error message.
  4. Otherwise, print the result of the division.

Solution:

numerator = float(input("Enter the numerator: "))
denominator = float(input("Enter the denominator: "))

try:
    result = numerator / denominator
except ZeroDivisionError:
    print("Error: Division by zero is not allowed.")
else:
    print(f"The result is {result}.")

Output:

Enter the numerator: 10
Enter the denominator: 0
Error: Division by zero is not allowed.

Exercise 9.2.3: Safe List Indexing

Write a program that tries to access an element in a list by its index given by the user. If an IndexError occurs, display an error message.

Instructions:

  1. Create a list with some elements.
  2. Prompt the user for an index.
  3. Use a try-except block to access the element at the given index.
  4. If an IndexError occurs, print an error message.
  5. Otherwise, print the accessed element.

Solution:

my_list = [10, 20, 30, 40, 50]
index = int(input("Enter the index of the element to retrieve: "))

try:
    element = my_list[index]
except IndexError:
    print(f"Error: The index '{index}' is out of range.")
else:
    print(f"The element at index {index} is {element}.")

Output:

Enter the index of the element to retrieve: 7
Error: The index '7' is out of range.