Three tools today, each answering a different question: how do I avoid loading everything at once, how do I keep only unique items, and how do I look something up fast?
1. Iterables, Iterators and Generators
- An iterable is anything you can loop over: a list, a tuple, a string.
- An iterator is what produces those values one at a time.
- A generator is a function that returns an iterator instead of a finished value.
def first_n(n):
for i in range(n):
yield i # pause here, hand back one value, resume on the next request
returncomputes everything, then hands it over. For a large dataset that’s a lot of memory at once.yieldhands back one value and pauses, resuming exactly where it left off.
Why it matters: downloading 100 files, you can process file 1 the moment it arrives instead of waiting for all 100.
Two things that surprise people:
- Calling a generator function runs no code. It gives you a generator object; the body runs when you iterate.
- A generator is consumed once. Loop it twice and the second pass is empty.
This is the same machinery as the generator expression with next() from yesterday.
2. Sets: Unique Things
nums = [1, 2, 2, 3, 3, 3]
unique = set(nums) # {1, 2, 3}
s = {1, 2, 3} # literal
empty = set() # {} would give you an empty DICTIONARY
s.add(4) # add, not append
Set operations:
a & b # intersection — in both
a - b # difference — in a, not in b
a | b # union — everything, no duplicates
Two rules to remember:
- Sets are unordered. Don’t expect insertion order back.
- Items must be hashable, so a list can’t go inside a set. A tuple can.
Converting a list to a set is the fastest way to strip duplicates.
3. Dictionaries: Key → Value
Like a phone directory: look up a name, get a number.
prefs = {"khaja": "dark", "amin": "light"}
prefs["khaja"] # "dark"
prefs["chandra"] = "dark" # add
prefs["amin"] = "dark" # update
prefs["nobody"] # KeyError!
prefs.get("nobody", "dark") # safe — returns the default
- Keys must be unique. Values can be anything and can repeat.
- Built for lookups — mapping user IDs to preferences, or session IDs to user data (exactly this morning’s agent problem).
- Dictionaries keep insertion order in modern Python, unlike sets.
- Always use
.get()when the key comes from user input.
A real example: mapping a course name to its destination folder, so an upload script knows where each file belongs.
4. Choosing the Right One
| Need | Use |
|---|---|
| Ordered, changeable collection | List |
| Ordered, fixed collection | Tuple |
| Uniqueness, fast membership tests | Set |
| Fast lookup by key, mapping | Dictionary |
| Large or streaming sequences | Generator |
Don’t memorise methods. Know what each structure is for, and the methods are a search away.
✅ Homework
For next class, be ready to say which data structure you’d pick for a set of build scenarios, and why. The reasoning matters more than the answer.
