Fundamentals 15 min read

Master Python Debugging: From Print Statements to Advanced Error Handling

This comprehensive guide explores Python debugging and error handling techniques—from simple print statements and logging to pdb, structured logging, retry mechanisms, circuit breakers, testing strategies, and remote debugging—providing a complete toolkit for building robust and maintainable Python applications.

Python Crawling & Data Mining
Python Crawling & Data Mining
Python Crawling & Data Mining
Master Python Debugging: From Print Statements to Advanced Error Handling

Introduction

Effective debugging and error handling are essential for building robust Python applications. This guide walks through basic print debugging, the logging module, the pdb debugger, advanced techniques, structured logging, retry mechanisms, circuit breaker pattern, testing strategies, and remote debugging.

Basic Debugging

Print debugging

def calculate_discount(price, discount_rate):
    print(f"[DEBUG] price={price}, discount_rate={discount_rate}")
    if discount_rate < 0 or discount_rate > 1:
        print(f"[WARNING] Invalid discount_rate: {discount_rate}")
        return price
    discounted_price = price * (1 - discount_rate)
    print(f"[DEBUG] result={discounted_price}")
    return discounted_price

Logging

import logging
logging.basicConfig(level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
logger.debug("Starting business logic")
# ... use logger.info, logger.error, etc.

Exception Handling

Try‑except structure

def read_file_safely(filename):
    try:
        with open(filename, 'r', encoding='utf-8') as file:
            return file.read()
    except FileNotFoundError:
        print(f"Error: file {filename} not found")
        return None
    except PermissionError:
        print(f"Error: no permission to read {filename}")
        return None
    except Exception as e:
        print(f"Unknown error: {e}")
        return None

Custom exception

class ValidationError(Exception):
    def __init__(self, message, field_name=None, value=None):
        self.message = message
        self.field_name = field_name
        self.value = value
        super().__init__(self.message)
    def __str__(self):
        if self.field_name:
            return f"{self.field_name} validation failed: {self.message} (value: {self.value})"
        return self.message

Advanced Debugging

pdb and breakpoint()

import pdb
pdb.set_trace()
# or Python 3.7+
breakpoint()

Third‑party tools (ipdb)

import ipdb
ipdb.set_trace()

Logging Best Practices

Complete logging configuration

LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'detailed': {'format': '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'},
        'simple': {'format': '%(levelname)s: %(message)s'}
    },
    'handlers': {
        'console': {'class': 'logging.StreamHandler', 'level': 'INFO', 'formatter': 'simple'},
        'file': {'class': 'logging.FileHandler', 'level': 'DEBUG', 'formatter': 'detailed', 'filename': 'app.log', 'mode': 'a'},
        'error_file': {'class': 'logging.FileHandler', 'level': 'ERROR', 'formatter': 'detailed', 'filename': 'errors.log', 'mode': 'a'}
    },
    'loggers': {
        '': {'handlers': ['console', 'file', 'error_file'], 'level': 'DEBUG', 'propagate': True},
        'app.module': {'handlers': ['file'], 'level': 'DEBUG', 'propagate': False}
    }
}
logging.config.dictConfig(LOGGING_CONFIG)

Error‑Handling Patterns

Retry decorator

def retry(max_attempts=3, delay=1, backoff=2, exceptions=(Exception,)):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            attempts, current_delay = 0, delay
            while attempts < max_attempts:
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    attempts += 1
                    if attempts == max_attempts:
                        raise
                    time.sleep(current_delay)
                    current_delay *= backoff
        return wrapper
    return decorator

Circuit breaker

class CircuitBreaker:
    def __init__(self, failure_threshold=3, reset_timeout=10):
        self.failure_threshold = failure_threshold
        self.reset_timeout = reset_timeout
        self.failures = 0
        self.last_failure_time = None
        self.state = "CLOSED"
    # methods can_execute, record_success, record_failure ...

Testing and Debugging Integration

Assertions

def process_data(data):
    assert data is not None, "Data cannot be None"
    assert isinstance(data, list), "Data must be a list"
    assert len(data) > 0, "Data cannot be empty"
    # processing logic
    return result

Unit tests with debugging

import unittest
class TestDebugging(unittest.TestCase):
    def test_error_handling(self):
        with self.assertRaises(ValueError):
            raise ValueError("test error")

Production Debugging

Remote debugging with debugpy

import debugpy
debugpy.listen(("0.0.0.0", 5678))
print("Waiting for debugger...")
debugpy.wait_for_client()
print("Debugger attached!")

Checklist

✅ Add appropriate assertions

✅ Handle possible exceptions

✅ Sufficient logging

✅ Unit test coverage

✅ User‑friendly error messages

✅ No sensitive data in logs

✅ Proper log levels for production

✅ Monitoring and alerting

✅ Effective recovery strategies

Conclusion

Combining systematic debugging, structured logging, robust exception handling, and automated testing creates resilient Python programs that are easier to maintain and scale.

PythonAssertionsPdb
Python Crawling & Data Mining
Written by

Python Crawling & Data Mining

Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.