“It worked fine during testing, but it throws an error once it’s live!”“
“This exception message is so confusing, where did it go wrong?”“
“I fixed one bug, but three new bugs popped up…”
Does this experience sound familiar? Don’t worry, today I’m going to help you master the ultimate weapon for Python debugging:
Using PyCharm breakpoints along with log analysis, you can quickly pinpoint the issues in your code like a seasoned detective!
First: Master the art of breakpoint debugging—make the code execution process “transparent”.
Breakpoint debugging is like giving your code a “slow-motion replay” feature, allowing you to observe the program’s execution step by step.
Common pain points of traditional debugging:
1. Blindly adding print statements, which is inefficient.
2. Unable to observe the internal state of the program during execution.
3. Difficult to reproduce complex error scenarios.
The complete process of breakpoint debugging:
python
# Example: A function for calculating e-commerce inventory value with potential issues
def calculate_inventory_value(products):
total_value = 0
# Set a breakpoint here – click the area to the right of the line number
for product in products:
price = product.get(‘price’, 0)
quantity = product.get(‘stock’, 0)
discount = product.get(‘discount’, 1.0)
# Calculate the value of a single product
product_value = price * quantity * discount
total_value += product_value
# Observe variable changes – check in the Debug window
print(f”Product: {product.get(‘name’)}, Value: {product_value}”)
return total_value
# Test data
sample_products = [
{‘name’: ‘Wireless Headphones’, ‘price’: 299, ‘stock’: 50, ‘discount’: 0.9},
{‘name’: ‘Power Bank’, ‘price’: 159, ‘stock’: 30},
{‘name’: ‘Phone Case’, ‘price’: 49, ‘stock’: 100, ‘discount’: 0.8}
]
# Right-click in PyCharm and select “Debug” to run
result = calculate_inventory_value(sample_products)
print(f”Total inventory value: {result}”)
The core techniques of breakpoint debugging:
Set breakpoints at critical lines of code, and the program will automatically pause when it reaches this point.
Use Step Over to execute line by line and observe the program flow.
Utilize Step Into to dive into function internals and see detailed execution processes.
Monitor variable value changes in real-time through the Variables window.
Isn’t it amazing? It’s like having the superpower of “time pause”, allowing you to check the code state at any moment!
Second: Make good use of log analysis—install a “black box” for your program.
If breakpoint debugging is a “microscope”, then log analysis is the program’s “dashcam”, recording the complete execution trajectory of the code.
The three important levels of log recording:
DEBUG level: Records detailed technical details.
INFO level: Records normal business processes.
ERROR level: Records errors and exceptions.
Implementing a complete solution for intelligent log recording:
python
import logging
import os
from datetime import datetime
def setup_logging():
# Create logs directory
if not os.path.exists(‘logs’):
os.makedirs(‘logs’)
# Configure log format
log_format = ‘%(asctime)s – %(name)s – %(levelname)s – %(message)s’
# Set log level and output file
logging.basicConfig(level=logging.DEBUG, format=log_format, handlers=[
logging.FileHandler(f’logs/debug_{datetime.now().strftime(“%Y%m%d”)}.log’),
logging.StreamHandler() # Also output to console
])
def process_user_order(user_data, order_items):
logger = logging.getLogger(‘Order Processing’)
try:
logger.info(f”Starting to process order for user {user_data[‘user_id’]}.”)
total_amount = 0
for item in order_items:
logger.debug(f”Processing item: {item[‘name’]}, Price: {item[‘price’]}”)
if item[‘price’] <= 0:
logger.warning(f”Item {item[‘name’]} has an abnormal price: {item[‘price’]}”)
total_amount += item[‘price’] * item[‘quantity’]
logger.info(f”Total amount calculated: {total_amount}”)
return total_amount
except Exception as e:
logger.error(f”Order processing failed: {str(e)}”, exc_info=True)
return None
# Initialize logging system
setup_logging()
# Test log functionality
test_user = {‘user_id’: ‘U1001’, ‘name’: ‘Zhang San’}
test_order = [{‘name’: ‘Python Programming Book’, ‘price’: 89, ‘quantity’: 2}, {‘name’: ‘Wireless Mouse’, ‘price’: 159, ‘quantity’: 1}]
result = process_user_order(test_user, test_order)
The logging system is like the “autobiography” of the program, detailing every important moment, making problem identification more reliable!
Third: Combination usage techniques—building a complete debugging system.
Using breakpoint debugging or log analysis alone is already very useful, but the combination of both can produce an effect greater than the sum of its parts.
Practical plan for building a debugging system:
python
import logging
class DebugHelper:
def __init__(self, module_name):
self.logger = logging.getLogger(module_name)
def debug_function(self, func):
“””Decorator: Adds debugging support to a function”””
def wrapper(*args, **kwargs):
self.logger.info(f”Function {func.__name__} started executing.”)
self.logger.debug(f”Parameters: args={args}, kwargs={kwargs}”)
try:
result = func(*args, **kwargs)
self.logger.info(f”Function {func.__name__} executed successfully.”)
return result
except Exception as e:
self.logger.error(f”Function {func.__name__} execution failed: {str(e)}”)
raise
return wrapper
# Usage example
debug_tool = DebugHelper(‘Inventory Management’)
@debug_tool.debug_function
def update_product_stock(product_id, new_stock):
if new_stock < 0:
raise ValueError(“Stock quantity cannot be negative”)
print(f”Updating product {product_id} stock to {new_stock}”)
return True
# Test various scenarios
try:
update_product_stock(‘P1001’, 50) # Normal case
update_product_stock(‘P1002’, -5) # Exception case
except Exception as e:
print(f”Caught exception: {e}”)
The advantages of this debugging system:
Logs provide a complete execution history.
Breakpoint debugging allows for in-depth analysis of specific problem scenarios.
The decorator pattern separates debugging code from business logic.
Conditional breakpoints only trigger under specific conditions, improving debugging efficiency.
Mastering these debugging techniques will transform you from “blind guessing” to “precise localization”:
Breakpoint debugging lets you see every detail of code execution.
Log analysis provides a complete timeline of when issues occur.
Combining both makes the debugging process comprehensive and in-depth.
Remember these three debugging principles:
Good programmers don’t avoid bugs; they fix them quickly.
More debugging tools aren’t necessarily better; the more refined, the better.
Problem-solving isn’t about luck; it’s about a systematic approach.
Start practicing these techniques now! Open your PyCharm and try using breakpoint debugging and log analysis in your next project. When you first quickly locate and resolve a complex issue through debugging, you’ll truly experience the sense of achievement and control in programming.
Debugging is not the enemy of programming; it is the best teacher for understanding code. From today on, let debugging become your powerful assistant in programming, turning every bug into an opportunity for progress!
Click on the card above to follow the blogger “Poetry and Backpack”