How to catch bugs in Python: Full guide on try, except, finally

онлайн тренажер по питону
Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Error Handling in Python with try, except, finally

Working with errors is an integral part of developing high-quality and reliable software. Even the most experienced developers are not immune to errors during program execution. To prevent such situations from causing a complete application crash, Python provides powerful tools for exception handling.

This guide discusses the proper use of try, except, and finally constructs to create error-resistant code.

Fundamentals of Exception Handling in Python

What is Error Handling

Error handling in Python allows you to catch exceptions that occur during program execution. Instead of abruptly terminating the application, the system performs specific actions to correctly handle the problematic situation.

Key Elements of the Exception Handling System

The error handling system in Python is based on three main blocks:

  • try — a code block where an exception may occur.
  • except — a block for handling a specific type of error.
  • finally — a code block that executes regardless of the result.

Basic Structure of the try-except-finally Construct

Syntax of the Main Construct

try:
    # Code that may raise an exception
    pass
except SpecificError:
    # Code to handle the specific error
    pass
finally:
    # Code that executes in any case
    pass

Practical Application of the Basic Structure

try:
    user_input = input("Enter a number: ")
    number = int(user_input)
    print(f"You entered the number: {number}")
except ValueError:
    print("Error: You must enter a valid number")
finally:
    print("Operation complete")

If the input is correct, the program will output the entered number. In case of incorrect input, an error message will be displayed. The finally block will execute in any scenario.

Handling Different Types of Exceptions

Multiple Error Handling

Python allows handling different types of exceptions using multiple except blocks:

try:
    dividend = 10
    divisor = 0
    result = dividend / divisor
except ZeroDivisionError:
    print("Division by zero is not allowed")
except ValueError:
    print("Invalid data format detected")
except TypeError:
    print("Incompatible data types for the operation")
finally:
    print("Mathematical operation processing complete")

Error Handling Without the finally Block

The finally block is not a required component. If it is absent, the program handles the exception and continues execution:

try:
    data_list = [1, 2, 3, 4, 5]
    element = data_list[10]  # Attempt to access a non-existent index
except IndexError:
    print("Attempt to access an index outside the list bounds")

Getting Detailed Information About Exceptions

Using the as Keyword

To get detailed information about an exception, use the construct with the as keyword:

try:
    calculation = 15 / 0
except ZeroDivisionError as error:
    print(f"Error detected: {error}")
    print(f"Error type: {type(error).__name__}")

Execution result:

Error detected: division by zero
Error type: ZeroDivisionError

Universal Handling of All Exceptions

In some cases, it is necessary to catch any possible exceptions:

try:
    potentially_risky_operation()
except Exception as error:
    print(f"An unexpected exception occurred: {error}")
    print("The program continues to run in emergency mode")

It is important to use this approach with caution, as it can hide critical errors that require special handling.

Applying the finally Block

Main Purpose of finally

The finally block is designed to execute code that must be executed regardless of whether an exception occurred or not. It is most often used to release system resources.

Working with Files and Resources

file_handle = None
try:
    file_handle = open("important_data.txt", "r", encoding="utf-8")
    content = file_handle.read()
    processed_data = process_file_content(content)
except FileNotFoundError:
    print("The specified file was not found in the system")
except PermissionError:
    print("Insufficient rights to access the file")
except UnicodeDecodeError:
    print("Encoding error when reading the file")
finally:
    if file_handle and not file_handle.closed:
        file_handle.close()
        print("File closed correctly")

Modern Approaches to Resource Management

Context Manager with

For working with files and other resources, it is recommended to use the context manager with:

try:
    with open("data_file.txt", "r", encoding="utf-8") as file:
        file_content = file.read()
        lines_count = len(file_content.split('\n'))
        print(f"The file contains {lines_count} lines")
except FileNotFoundError:
    print("File not found")
except IOError:
    print("Input/output error when working with the file")

Advantages of the context manager:

  • Automatic file closing
  • Guaranteed resource release
  • Cleaner and more readable code
  • Prevention of memory leaks

Advanced Exception Handling Techniques

Handling a Group of Exceptions

Python allows handling multiple types of exceptions in one except block:

try:
    user_data = input("Enter a number for calculation: ")
    number = float(user_data)
    result = 100 / number
    print(f"Calculation result: {result}")
except (ValueError, TypeError):
    print("Data conversion error")
except ZeroDivisionError:
    print("Division by zero is not possible")

Creating Robust Functions

Exception handling inside functions increases their reliability:

def safe_mathematical_division(dividend, divisor):
    """Safe division function with error handling"""
    try:
        result = dividend / divisor
        return result
    except ZeroDivisionError:
        return "Operation not possible: division by zero"
    except TypeError:
        return "Error: unsupported data types"
    except Exception as error:
        return f"Unexpected error: {error}"

# Function usage
print(safe_mathematical_division(10, 2))    # 5.0
print(safe_mathematical_division(10, 0))    # Operation not possible: division by zero
print(safe_mathematical_division("10", 2))  # Error: unsupported data types

Types of Exceptions in Python

Most Common Exceptions

Python provides an extensive hierarchy of built-in exceptions:

  • ValueError — incorrect value with the correct data type
  • TypeError — operation applied to an object of an inappropriate type
  • IndexError — access to an index outside the sequence bounds
  • KeyError — missing key in the dictionary
  • FileNotFoundError — file or directory not found
  • PermissionError — insufficient rights to perform the operation
  • AttributeError — the object does not have the specified attribute
  • ImportError — inability to import the module
  • SyntaxError — syntax error in the code
  • IndentationError — indentation errors in Python code

Exception Hierarchy

def demonstrate_exception_hierarchy():
    """Demonstration of various types of exceptions"""
    
    # ValueError - invalid value
    try:
        number = int("not a number")
    except ValueError as e:
        print(f"ValueError: {e}")
    
    # IndexError - invalid index
    try:
        items = [1, 2, 3]
        value = items[5]
    except IndexError as e:
        print(f"IndexError: {e}")
    
    # KeyError - missing key
    try:
        dictionary = {"a": 1, "b": 2}
        value = dictionary["c"]
    except KeyError as e:
        print(f"KeyError: {e}")
    
    # TypeError - invalid type
    try:
        result = "string" + 5
    except TypeError as e:
        print(f"TypeError: {e}")

Best Practices for Exception Handling

Principles of Effective Error Handling

When working with exceptions, adhere to the following principles:

  • Handle only the exceptions you can correctly handle
  • Avoid overly broad exception catching
  • Provide users with clear error messages
  • Log critical errors
  • Do not ignore exceptions without a valid reason

Error Logging

import logging

# Logging setup
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

def process_user_data(data):
    """Processing user data with logging"""
    try:
        processed = data.strip().upper()
        result = int(processed)
        logging.info(f"Successful data processing: {result}")
        return result
    except ValueError as e:
        logging.error(f"Data conversion error: {e}")
        return None
    except AttributeError as e:
        logging.error(f"Incorrect input data type: {e}")
        return None

Practical Recommendations

Creating Error-Resistant Code

Competent exception handling is the foundation for creating reliable applications. The try, except, and finally constructs provide controlled handling of both predictable and unexpected errors.

Key Usage Recommendations

  • Apply exception handling consciously and purposefully
  • Avoid catching all exceptions unless absolutely necessary
  • Always release system resources
  • Use context managers for working with files and connections
  • Provide informative error messages
  • Document the handled exceptions

Proper error handling improves code readability, simplifies the debugging process, and ensures stable operation of software in various operating conditions.

News