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
51: For Loops and Iteration
I see this all the time when I'm reviewing code from developers transitioning to Python from languages like C++ or Java: they treat the for loop as a glorified counter. They spend so much time worrying about the index—the i variable—that they forget the actual data they're trying to work with.
Stop using range(len()) to access list items
Here is a classic example of the "counter" mindset. Let's say you have a list of user email addresses and you want to print each one. A lot of learners write it like this:
emails = ["alice@example.com", "bob@example.com", "charlie@example.com"]
for i in range(len(emails)):
print(emails[i])
Technically, this works. But in Python, this is considered an "anti-pattern." You're creating a range of numbers, then using those numbers to look up an item in a list. It's verbose, it's slower, and it's exactly how we did things in 1995. You're adding an extra layer of mental overhead by tracking the index when you don't actually care about the number; you only care about the email.
Thinking of "for" as "for each"
In Python, the for loop is actually a "for-each" loop. It doesn't count; it iterates. It reaches into the collection and hands you the actual object, one by one.
emails = ["alice@example.com", "bob@example.com", "charlie@example.com"]
for email in emails:
print(email)
See the difference? email isn't a number; it's the actual string. This makes your code read like a sentence in English. I've always found that the more your code looks like a sentence, the fewer bugs you'll introduce because the logic becomes obvious.
Handling the "But I actually need the index!" problem
Now, I know what you're thinking: "What if I need to know the position of the item? What if I need to print 'User 1: alice@example.com'?"
You still shouldn't go back to range(len()). Instead, use enumerate(). This is a built-in function that gives you both the index and the item at the same time. It's the professional way to handle this scenario.
emails = ["alice@example.com", "bob@example.com", "charlie@example.com"]
for index, email in enumerate(emails, start=1):
print(f"User {index}: {email}")
Note that I used start=1. By default, Python starts counting at 0, but enumerate lets you shift that starting point so your output makes sense to humans.
Fine-tuning the flow with break and continue
Iteration isn't always a straight line from start to finish. Sometimes you need to bail out early or skip a specific item. That's where break and continue come in.
- break: Stops the loop entirely. Use this when you've found what you're looking for and there's no point in checking the rest of the list.
- continue: Skips the rest of the current block and jumps straight to the next item in the list.
Imagine you're searching for a specific "blacklisted" email in a list. You don't want to keep looking once you find it, and you want to skip over any empty strings in your data:
emails = ["alice@example.com", "", "malicious@spam.com", "bob@example.com"]
blacklist = "malicious@spam.com"
for email in emails:
if not email:
continue # Skip empty strings
if email == blacklist:
print("Security alert: Blacklisted email found!")
break # Stop searching immediately
Using continue keeps your code from becoming a giant mess of nested if statements, keeping the "happy path" of your logic aligned to the left margin of your editor.
📋 Practical Task
Filtering an Atmospheric Sensor Data Log
You have been given a list of temperature readings from a remote sensor. However, the sensor is glitchy: it occasionally records None values when it loses power, and it sometimes records "Impossible" readings (anything above 100°C or below -50°C) that should be ignored.
Your Task: Write a script that iterates through the sensor_readings list and calculates the average of the valid readings only.
Requirements:
- Use a
forloop to iterate through the list. - Use
continueto skipNonevalues and readings outside the valid range (-50 to 100). - Keep a running total of the valid temperatures and a count of how many valid readings were found.
- Print the final average.
sensor_readings = [22.5, 23.1, None, 105.2, 21.8, -60.0, None, 24.0, 22.9]There are no comments for now.