Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
150: Logging vs print for Diagnostics
Why can't I just keep using print() for my diagnostics?
Look, when you're hacking together a small script on your local machine, print() is great. It's fast. But the moment your code moves to a server or runs as a background task, print() becomes a liability. Why? Because prints are "dumb." They just dump text to the standard output. If your script crashes at 3:00 AM on a remote server, those print statements are gone unless you've manually redirected the entire shell output to a file, which is messy and imprecise.
I've spent way too many hours of my career hunting through massive text files for a specific "Here" or "Test 1" print statement I forgot to remove. With the logging module, you can categorize your messages. You can tell Python, "Only show me the critical errors right now, but keep the detailed debug info in the background in case I need it later."
How do I actually set this up without it feeling over-engineered?
You don't need a complex configuration file to get started. For most of your projects, logging.basicConfig() is all you need. Let's imagine we're building a price tracker that scrapes a website. Instead of printing "Checking price...", we use the logger.
import logging
# Basic config: set the level and the format
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def check_price(item_id):
logging.debug(f"Fetching data for item {item_id}...")
# Imagine a network request happens here
success = False
if not success:
logging.error(f"Failed to retrieve price for {item_id}")
check_price("B07X123")
Notice the format argument. Now, every message automatically gets a timestamp and a severity level. You didn't have to manually type datetime.now() inside every single diagnostic message. That's a huge quality-of-life win.
What's the difference between DEBUG, INFO, WARNING, ERROR, and CRITICAL?
This is where people usually get tripped up. It's not a hard rule, but I follow this mental model:
- DEBUG: "The guts." Information that is only useful when you're actively trying to find a bug. (e.g., "Variable x is currently 42")
- INFO: "The heartbeat." General confirmation that things are working as expected. (e.g., "Price tracker started successfully")
- WARNING: "The yellow flag." Something odd happened, but the app is still running. (e.g., "API response took longer than 2 seconds")
- ERROR: "The red flag." A specific operation failed. (e.g., "Could not connect to the database")
- CRITICAL: "The panic button." The entire program must stop immediately. (e.g., "Disk full, cannot write logs or data")
The magic happens when you change the level in basicConfig(). If you set it to logging.WARNING, all those DEBUG and INFO messages simply vanish from your output. You don't have to delete your code; you just turn down the volume.
Can I save these logs to a file instead of just watching them scroll by?
Absolutely. And in a real production environment, you almost always should. You just add a filename argument to your config. I usually recommend using a specific filename so you don't accidentally clutter your root directory.
logging.basicConfig(
filename='app_diagnostics.log',
filemode='a', # 'a' for append, 'w' to overwrite every time
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logging.info("Application started. Logging to file now.")
One tip from the trenches: be careful with filemode='w'. If you use 'w', you'll wipe your logs every time the script restarts. Stick with 'a' (append) unless you have a very specific reason not to. In larger systems, we use "Rotating File Handlers" so the log files don't grow to 10GB and eat the whole hard drive, but for now, a simple file is a massive upgrade over print().
📋 Practical Task
Exercise: Converting the Price Tracker to a Professional Logger
You have been handed a legacy script that uses print() for everything. Your task is to replace the prints with a proper logging system.
Requirements:
- Import the
loggingmodule. - Configure the logger to save messages to a file named
tracker.log. - Set the logging level to
DEBUGso all messages are captured. - Replace the
print("Starting scrape...")with anINFOlog. - Replace the
print(f"Checking item {item}")with aDEBUGlog. - Replace the
print("Error: Website unreachable")with anERRORlog.
# STARTING CODE
def run_tracker(items):
print("Starting scrape...")
for item in items:
print(f"Checking item {item}")
# Simulate a failure for the last item
if item == "BrokenLink":
print("Error: Website unreachable")
run_tracker(["Laptop", "Mouse", "BrokenLink"])
# END STARTING CODE
There are no comments for now.