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
54: break, continue, and else on Loops
I was looking through some old log-parsing scripts the other day and realized how often we write loops that do more work than they need to. Most of the time, we aren't actually interested in every single item in a list; we're looking for one specific thing, or we're trying to filter out the garbage. Let's look at a real scenario: we have a list of server status messages, and we need to find if there's a "CRITICAL" failure.
The problem with searching until the end
If I just write a standard for loop, Python is going to visit every single element. Let's try it with a small list of logs:
logs = ["INFO: System boot", "INFO: Network up", "CRITICAL: Disk Failure", "INFO: User logged in", "INFO: Backup started"]
for log in logs:
if "CRITICAL" in log:
print("Found the error! Stopping search.")
# Imagine there is some expensive processing here
print(f"Processing {log}...")
If you run this, you'll notice that even after it prints "Found the error!", it keeps processing the rest of the logs. That's a waste of CPU cycles. In a real production environment with millions of lines of logs, that's a performance nightmare. I don't care about the "User logged in" message if the disk has already failed.
Cutting the loop short
This is where break comes in. It's a blunt instrument: it tells Python to drop out of the loop immediately, regardless of how many items are left in the sequence. Let's tweak the code:
for log in logs:
if "CRITICAL" in log:
print("Found the error! Stopping search.")
break
print(f"Processing {log}...")
Now, the moment "CRITICAL: Disk Failure" is hit, the loop terminates. We didn't even look at the "User logged in" log. It's clean, it's fast, and it's exactly what we want when searching for a unique trigger.
Skipping the noise
But what if we have some "noise" in our data? Let's say our log list contains some empty strings or "DEBUG" messages that we just want to ignore entirely without stopping the whole search. I don't want to wrap my entire logic inside a giant if block—that leads to "arrow code" (where your indentation keeps pushing further and further to the right).
Instead, I'll use continue. While break kills the loop, continue just kills the current iteration and jumps straight to the next item.
logs = ["INFO: Boot", "", "DEBUG: Temp check", "CRITICAL: Disk Failure", "INFO: User login"]
for log in logs:
if not log or "DEBUG" in log:
continue # Skip these and move to the next log immediately
if "CRITICAL" in log:
print("Found the error!")
break
print(f"Analyzing {log}...")
I personally prefer continue for "guard clauses." By putting the skips at the top, the rest of my loop stays flat and readable. If the log is empty or a debug message, we just bounce back to the top of the loop and grab the next one.
Handling the 'Not Found' scenario
Here is where things get weird. Usually, if we're searching for something, we need to know if we never found it. The old-school way is to create a "flag" variable (like found = False) and flip it to True inside the if block. It works, but it's clunky.
Python has a feature that feels almost like a mistake because the naming is confusing: the else block on a loop. In a loop, else doesn't mean "if the loop didn't run"; it means "if the loop finished naturally without hitting a break."
Let's try it. I'll use a list with no critical errors this time:
safe_logs = ["INFO: Boot", "INFO: Network up"]
for log in safe_logs:
if "CRITICAL" in log:
print("Found it!")
break
else:
print("Search complete: No critical errors found.")
Because the loop finished all its iterations without ever hitting the break statement, the else block executes. If I change one of those logs to "CRITICAL", the break triggers, and the else block is skipped entirely. It's a very elegant way to handle "search and fail" logic, even if the keyword else feels slightly misplaced here.
📋 Practical Task
Exercise: The Malicious URL Filter
You are building a security filter for a web proxy. You have a list of requested URLs, some of which are empty, some of which are safe, and some of which are known malicious domains.
Write a script that does the following:
- Iterates through a list of URLs:
["google.com", "", "malware-site.net", "python.org", "evil-domain.com"]. - If a URL is an empty string, use
continueto skip it. - If a URL contains the word "malware" or "evil", print "Security Alert: Malicious site blocked!" and use
breakto stop all further processing immediately. - If the loop finishes without finding any malicious sites, use an
elseblock to print "Scan complete: All URLs are safe."
There are no comments for now.