โณ Loading Python Engine...

๐Ÿ“Š Day 09 : Loops

๐ŸŽฏ Enterprise Objective

Iteration is the engine of data processing. Today we graduate from basic loops to professional iteration patterns. You will learn to write memory-efficient pipelines using generators and the itertools module, allowing you to process gigabytes of data seamlessly without crashing your system.

๐Ÿ“‹ Strategic Overview

#TopicKey ConceptCore Use Case
1for loopsIterables & IteratorsStandard data traversal
2while loopsCondition-basedPolling & Pagination
3Loop Controlcontinue, for...elseFiltering & Search logic
4Patternsenumerate(), zip()Multi-list processing
5GeneratorsyieldO(1) Memory pipelines
6Expressions(expr for x in data)Lazy reductions
7Itertoolschain, combinationsCombinatorial math

1. For Loops & Iterables : Data Traversal

๐Ÿ” What is it?

A for loop in Python iterates over an iterable (like a list, string, or dictionary). Unlike C-style loops that use index counters, Python's for loop extracts the actual items directly. Under the hood, it calls iter() to get an iterator, and next() until it hits a StopIteration error.

Iterable TypeIteration YieldsExample
List / TupleItemsfor item in [1, 2]:
StringCharactersfor char in 'abc':
DictionaryKeysfor key in {'a': 1}:
SetItems (Unordered)for item in {1, 2}:
File objectLinesfor line in open('f.txt'):

๐Ÿ’ผ Why Data Analysts Care

โ€ข Data Processing: Iterating over rows in a dataset or JSON objects in an API response

โ€ข File Parsing: Reading gigabytes of log files line-by-line without loading them into memory

โš ๏ธ Modifying While Iterating

Never modify a list (adding/removing items) while iterating over it with a for loop. It will skip elements or crash. Iterate over a copy instead: for item in my_list.copy():.

In [ ]:

๐Ÿงช Concept Checks: For Loops

Q1. Write a for loop that iterates over data = [10, 20, 30] and prints the square of each number.

In [ ]:

Q2. Iterate over the string "Python" and print each character multiplied by 3 (e.g., "PPP").

In [ ]:

Q3. Create a dictionary d = {"a": 1, "b": 2}. Use a standard for loop (which yields keys) to print both key and value: d[key].

In [ ]:

Q4. Demonstrate the modification trap: iterate over lst = [1, 2, 3, 4], and if the item is even, remove it using lst.remove(). Print the list. Did it work correctly? Explain.

In [ ]:

Q5. Fix the previous code by iterating over a slice copy lst[:]. Print the corrected list.

In [ ]:

2. While Loops & State Machines : Condition-Based Iteration

๐Ÿ” What is it?

A while loop runs as long as a condition evaluates to True. It is used when the number of iterations is unknown beforehand (e.g., waiting for an API response, polling a database, or reading user input until they type 'quit').

# Polling pattern
while not db.is_ready():
    time.sleep(1)
    print("Waiting...")

๐Ÿ’ผ Why Data Analysts Care

โ€ข API Pagination: Fetching pages of data until next_page_token is null

โ€ข Retry Logic: Attempting to connect to a server up to 5 times before failing

โ€ข Simulation: Running a simulation until a specific convergence threshold is met

โš ๏ธ Infinite Loops

Always ensure the condition inside a while loop will eventually become False, or provide a break statement. Otherwise, your program will freeze forever.

In [ ]:

๐Ÿงช Concept Checks: While Loops

Q1. Write a while loop that prints powers of 2 (1, 2, 4, 8...) as long as the value is less than 100.

In [ ]:

Q2. Write a while loop to find the first number divisible by both 7 and 13, starting your search at n = 1. Print it.

In [ ]:

Q3. Create a list items = ["a", "b", "c"]. Use a while items: loop and .pop() to empty the list, printing each item.

In [ ]:

Q4. Write a simulation: start with money = 100. In a while loop, subtract a random amount between 10-20 until money is < 0. Count iterations.

In [ ]:

Q5. What is the most common cause of an infinite loop? Write a tiny script demonstrating one (and comment it out so it doesn't crash the notebook!).

In [ ]:

3. Loop Control : Break, Continue, Pass & Else

๐Ÿ” What is it?

Python provides keywords to alter loop flow. break exits the loop entirely. continue skips the rest of the current iteration and jumps to the next. Python also has a unique for...else construct where the else block runs only if the loop completes without hitting a break.

KeywordEffectCommon Use
continueSkip to next iterationGuard clauses inside loops (filtering)
breakExit loop immediatelyEarly exit when item is found
passDo nothingPlaceholder for unimplemented code
elseRuns if NO break occurred"Search failed" logic

๐Ÿ’ผ Why Data Analysts Care

โ€ข Data Filtering: Use continue to skip invalid rows without deeply nesting if statements

โ€ข Search Algorithms: Use break to stop searching a massive dataset once the target is found

โ€ข Validation: Use for...else to verify that ALL items pass a check

๐Ÿง  Pro Tip

The for...else naming is confusing. Think of it as for...no_break. It's the most Pythonic way to perform a 'search and report if not found' pattern.

In [ ]:

๐Ÿงช Concept Checks: Loop Control

Q1. Write a loop from 1 to 10. Use continue to skip numbers divisible by 3. Print the rest.

In [ ]:

Q2. Given data = [1, 5, -2, 8, -4], iterate and print positive numbers. Use break to stop completely if you hit a negative number.

In [ ]:

Q3. Write a for...else loop that checks if a prime number 11 is divisible by any number from 2 to 10. If not, the else block prints "It is prime".

In [ ]:

Q4. Write a while True: loop that increments a counter. Use an if statement and break to exit when the counter reaches 5. Print the counter.

In [ ]:

Q5. Why is pass useful? Write an empty function or loop using pass to show how it prevents a SyntaxError.

In [ ]:

4. Iteration Patterns : Pythonic Looping

๐Ÿ” What is it?

Python emphasizes readability. Instead of manually tracking indices with range(len(data)), Python provides elegant built-in functions: enumerate() (value + index), zip() (parallel iteration), and reversed() (backwards).

PatternGood Pythonic CodeBad C-Style Code
Index Trackingfor i, val in enumerate(lst):for i in range(len(lst)): val = lst[i]
Parallel Loopsfor a, b in zip(listA, listB):for i in range(len(listA)): a,b = listA[i], listB[i]
Reverse Loopfor val in reversed(lst):for i in range(len(lst)-1, -1, -1):

๐Ÿ’ผ Why Data Analysts Care

โ€ข Feature Engineering: Combining multiple columns using zip(col1, col2)

โ€ข Logging: Printing row numbers alongside data errors using enumerate(data, start=1)

โš ๏ธ Uneven Zip

zip() stops at the shortest iterable. If A has 5 items and B has 3, it only loops 3 times. Use itertools.zip_longest if you need to process all elements.
In [ ]:

๐Ÿงช Concept Checks: Iteration Patterns

Q1. Given cities = ["NY", "LA", "CHI"], use enumerate(..., start=1) to print "1. NY", "2. LA", etc.

In [ ]:

Q2. Given keys = ["a", "b", "c"] and vals = [1, 2, 3], use zip in a dictionary comprehension to map them: {k: v}. Print the dict.

In [ ]:

Q3. What happens if you zip [1, 2, 3] with ["A", "B"]? Write the loop and print the results to see the truncation.

In [ ]:

Q4. Loop backwards from 10 to 1 using reversed(range(1, 11)). Print the numbers.

In [ ]:

Q5. Combine patterns: use enumerate(zip(names, scores)) to print the index, name, and score all at once. Try it!

In [ ]:

5. Generators & yield : Lazy Memory-Efficient Evaluation

๐Ÿ” What is it?

A generator is a special function that returns an iterator. Instead of computing an entire list and storing it in memory, it uses the yield keyword to produce values one at a time. It pauses its state between yields.

# Normal Function (Eats RAM)
def get_millions():
    return [x for x in range(1_000_000)] # list in memory

# Generator (O(1) Memory)
def yield_millions():
    for x in range(1_000_000):
        yield x  # yields one by one

๐Ÿ’ผ Why Data Analysts Care

โ€ข Big Data Processing: Reading a 50GB CSV file line-by-line without crashing your laptop

โ€ข Infinite Streams: Processing real-time sensor data or Kafka event streams

โ€ข API Pagination: Yielding records page-by-page as they are requested

โš ๏ธ Generators are Single-Use

Once a generator is exhausted (loop finishes), it is empty. You cannot iterate over it a second time. You must create a new generator object.

In [ ]:

๐Ÿงช Concept Checks: Generators

Q1. Write a generator function countdown(n) that yields numbers from n down to 1. Test it in a loop.

In [ ]:

Q2. Demonstrate that generators are single-use: create a generator, loop over it once, then try to loop over it again. What happens?

In [ ]:

Q3. Write a generator fibonacci(limit) that yields Fibonacci numbers up to a maximum value. Print the results.

In [ ]:

Q4. Create a generator that yields random numbers between 1-10 infinitely. Use next() to pull 3 numbers from it manually.

In [ ]:

Q5. Why is yield better than return when parsing a massive log file?

In [ ]:

6. Generator Expressions : Inline Lazy Data

๐Ÿ” What is it?

A generator expression is exactly like a list comprehension, but it uses parentheses () instead of square brackets []. It creates a generator object instead of a list, saving massive amounts of memory.

SyntaxObject CreatedEvaluationMemory
[x for x in data]listEager (All at once)High
(x for x in data)generatorLazy (One by one)Low O(1)

๐Ÿ’ผ Why Data Analysts Care

โ€ข Math Reductions: sum(x**2 for x in data) โ€” computes the sum without creating a temporary list

โ€ข Pipelining: Chain multiple generator expressions to create a clean, memory-efficient data pipeline

๐Ÿง  Pro Tip

When passing a generator expression as the ONLY argument to a function, you can omit the extra parentheses: sum(x2 for x in range(10)) instead of sum((x2 for x in range(10))).

In [ ]:

๐Ÿงช Concept Checks: Generator Expressions

Q1. Write a generator expression for the cubes of numbers 1-10. Assign it to gen. Print next(gen) twice.

In [ ]:

Q2. Given data = ["10", "20", "invalid", "30"], write a generator expression that attempts to convert valid integers. Iterate and print.

In [ ]:

Q3. Compute the sum of the first 10,000 even numbers using sum() and a generator expression. Print the result.

In [ ]:

Q4. Use all() with a generator expression to check if all words in ["apple", "banana", "cherry"] have > 3 letters.

In [ ]:

Q5. Measure the memory difference (sys.getsizeof()) between [x for x in range(10000)] and (x for x in range(10000)).

In [ ]:

7. The itertools Module : Professional Iteration

๐Ÿ” What is it?

The itertools module is a standard library toolkit for creating and combining iterators. It provides fast, memory-efficient tools for combinatorial math, grouping, and advanced looping patterns.

Key Itertools:

FunctionPurposeExample
chain(A, B)Combine iterables sequentiallychain([1,2], [3,4]) โ†’ 1,2,3,4
combinations(A, 2)All unique pairs(A,B), (A,C), (B,C)
permutations(A, 2)All ordered pairs(A,B), (B,A), (A,C)...
cycle(A)Infinite loop over A1,2,1,2,1,2...
groupby(A, key)Group adjacent duplicatesGrouping sorted data

๐Ÿ’ผ Why Data Analysts Care

โ€ข Feature Interactions: Generating all pairs of columns using combinations for machine learning

โ€ข Flattening Data: Using chain.from_iterable(list_of_lists) to flatten nested structures efficiently

โš ๏ธ Infinite Itertools

Tools like cycle, count, and repeat generate infinite streams. Always use a break condition or zip them with a finite sequence, otherwise your program will hang.

In [ ]:

๐Ÿงช Concept Checks: Itertools

Q1. Import itertools. Use chain() to loop over [1,2,3], (4,5), and {"A", "B"} in a single for loop. Print each item.

In [ ]:

Q2. Use itertools.combinations() to find all 3-person teams from ["Alice", "Bob", "Charlie", "David"]. Print them.

In [ ]:

Q3. Use itertools.permutations() on [1, 2, 3] with length 2. How many results are there compared to combinations?

In [ ]:

Q4. Write a for loop using itertools.cycle(["Red", "Green", "Blue"]). Use a manual counter to break after 7 prints.

In [ ]:

Q5. Flatten matrix = [[1, 2], [3, 4], [5, 6]] using itertools.chain.from_iterable(). Print the resulting list.

In [ ]:

๐Ÿ› ๏ธ Professional Practice Tasks

Theory is useless without muscle memory. Complete these tasks to solidify your understanding.

Task 1 (Data Paginator): Write a generator paginate(data, page_size) that yields chunks of a list. E.g., paginate([1,2,3,4,5], 2) yields [1,2], [3,4], [5]. Test it in a loop.

In [ ]:

Task 2 (CSV Reader Pipeline): Write two generator functions. read_lines(text) yields lines from a multi-line string. parse_csv(lines) yields lists of values. Chain them: for row in parse_csv(read_lines(data)):.

In [ ]:

Task 3 (Prime Generator): Write a generator primes_up_to(n) that yields prime numbers. Use an internal while loop and math logic. Test with n=50.

In [ ]:

Task 4 (For-Else Search): Given a list of dictionaries (users), write a for...else loop that searches for a user with role == 'admin'. Break and print their name if found, else print 'No admin configured'.

In [ ]:

Task 5 (Cartesian Combinations): Given colors = ['red', 'blue'] and sizes = ['S', 'M', 'L'], use itertools.product to generate and print all possible color/size combinations.

In [ ]:

๐Ÿ’ป Pure Coding Interview Questions

Q1.

Write a generator fibonacci() that yields the Fibonacci sequence infinitely. Use itertools.islice to get the first 10.

In [ ]:

Q2.

Explain the difference between yield and return. What is a coroutine?

In [ ]:

Q3.

Write a function flatten(nested_list) using recursion and yield from to flatten arbitrarily deep lists.

In [ ]:

Q4.

Explain how for...else works. Write a code example showing a use case where it replaces a boolean flag.

In [ ]:

Q5.

Write a generator expression to find the sum of all odd numbers under 1,000,000. Why is this better than a list comprehension?

In [ ]:

Q6.

Implement a custom iterator class (with iter and next) that mimics the range(start, stop) function.

In [ ]:

Q7.

Write a function sliding_window(iterable, n) using itertools or generators to yield n-length windows. [1,2,3,4], n=2 -> (1,2), (2,3), (3,4).

In [ ]:

Q8.

Write a function that parses a log file line-by-line using a generator, filtering only lines containing 'ERROR'.

In [ ]:

Q9.

Explain the StopIteration exception. Write code that manually catches it while using next().

In [ ]:

Q10.

Write a function group_anagrams(words) using itertools.groupby. Why must the data be sorted first?

In [ ]:

Q11.

Implement a custom zip(*iterables) function using a while loop and next().

In [ ]:

Q12.

Write code using itertools.dropwhile and takewhile to extract a specific segment of data from a stream.

In [ ]:

Q13.

Explain what itertools.tee does and when you would need to use it to duplicate an iterator.

In [ ]:

Q14.

Write a function to generate all subsets (powerset) of a list using itertools.combinations.

In [ ]:

Q15.

Write a generator chunker(iterable, size) that works on ANY iterable (not just lists) using itertools.islice.

In [ ]:

Q16.

Implement an infinite prime number generator using a growing set of seen primes.

In [ ]:

Q17.

Write code showing the difference between itertools.combinations and itertools.combinations_with_replacement.

In [ ]:

Q18.

Write a function that uses a generator to find the first duplicate in a stream of data in O(1) memory.

In [ ]:

Q19.

Explain the memory profile of any([cond(x) for x in data]) vs any(cond(x) for x in data). Why does it matter?

In [ ]:

Q20.

Write a pipeline of three generator functions: read, filter, and transform. Connect them together.

In [ ]:

Q21.

Implement the Collatz conjecture as a generator yielding the sequence until it reaches 1.

In [ ]:

Q22.

Write a function that alternates yielding from two infinite generators using itertools.cycle or manual logic.

In [ ]:

Q23.

Explain why modifying a dictionary while iterating over it raises a RuntimeError. How do you safely delete keys in a loop?

In [ ]:

Q24.

Write a while loop that retries an API call (simulated function) with exponential backoff.

In [ ]:

Q25.

What is yield from? Write a function that uses it to chain two separate generator functions together.

In [ ]:

๐Ÿ“Š Day 9 Executive Summary

#TopicKey TakeawayProfessional Application
1for loopsIterates over iterablesData traversal without indices
2while loopsRuns while condition is truePolling, infinite streams, pagination
3Loop Controlbreak, continue, elseFast filtering, search resolution
4Iteration Patternsenumerate, zip, reversedElegant, readable data manipulation
5Generatorsyield pauses executionO(1) memory for massive datasets
6Gen Expressions(x for x in data)Inline lazy reductions (sum/any/all)
7ItertoolsStandard library iteration toolsCombinatorics, efficient chaining

โœ… Instructor's End-of-Day Checklist

โ€ข [ ] I understand how for loops work under the hood (iter() and next()).

โ€ข [ ] I know how to use while loops for unknown iteration counts (polling).

โ€ข [ ] I can use continue to filter and for...else for search operations.

โ€ข [ ] I always use enumerate() instead of range(len()).

โ€ข [ ] I understand how yield saves memory compared to returning a full list.

โ€ข [ ] I can write a generator expression for memory-efficient math reductions.

โ€ข [ ] I have completed all 5 practice tasks.

โ€ข [ ] I have reviewed all 25 interview questions.

*Next Up: Day 10 - Functions: Scope, Arguments, \args/\\kwargs, and Lambdas**