Weeks 7–10 — Dictionaries & Sets · String Methods & Formatting · Functions · Basic Capstone: CLI To-Do App
Use dictionaries for key-value storage and sets for unique collections. Learn dict comprehensions, set algebra, and when to choose each structure. Strings are immutable sequences with a rich method library. Learn to slice, search, replace, split, join, and format text for real-world use. Functions let you name and reuse blocks of logic. Learn def, return, default arguments, keyword arguments, and variable scope (LEGB rule). Combine everything from weeks 1–9 into a full command-line to-do application with add, list, complete, and delete commands. Optionally persist tasks to a JSON file.
What you'll learn
- 1Create, read, update, and delete dictionary entries
- 2Iterate over keys, values, and items
- 3Build dict comprehensions
- 4Perform union, intersection, and difference on sets
- 5Know when to use dict vs list vs set
- 6Use upper, lower, strip, replace, split, join
- 7Format strings with f-strings and format()
- 8Slice strings like lists
- 9Check membership with in and startswith/endswith
- 10Understand string immutability
- 11Define and call functions with def
- 12Return single and multiple values
- 13Use positional, keyword, and default arguments
- 14Understand the LEGB scope rule
- 15Write docstrings to document functions
- 16Integrate lists, dicts, functions, and loops in one project
- 17Handle user input robustly with error messages
- 18Save and load tasks from a JSON file
- 19Structure code into well-named functions
- 20Practice the full development loop: plan → code → test
Week 7 — Dictionaries & Sets
Use dictionaries for key-value storage and sets for unique collections. Learn dict comprehensions, set algebra, and when to choose each structure.
1. Dictionaries
Dictionaries store key-value pairs. Keys must be unique and hashable (usually strings or numbers).
person = {"name": "Alice", "age": 25, "city": "Seoul"}
print(person["name"]) # Alice
person["email"] = "a@ex.com" # add
person["age"] = 26 # update
del person["city"] # delete
print("age" in person) # True
print(person.get("phone", "N/A")) # N/A (safe access)2. Iterating Dictionaries
scores = {"Alice": 95, "Bob": 82, "Charlie": 78}
for name in scores: # keys
print(name)
for score in scores.values(): # values
print(score)
for name, score in scores.items(): # both
print(f"{name}: {score}")3. Sets
Sets hold unique, unordered items. Great for membership tests and set algebra.
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b) # union: {1,2,3,4,5,6}
print(a & b) # intersection: {3,4}
print(a - b) # difference: {1,2}
print(a ^ b) # symmetric diff: {1,2,5,6}4. Dict Comprehension
# Square each number
squares = {n: n**2 for n in range(1, 6)}
print(squares) # {1:1, 2:4, 3:9, 4:16, 5:25}
# Filter: only even keys
even = {k: v for k, v in squares.items() if k % 2 == 0}
print(even) # {2:4, 4:16}5. Common Mistakes
- dict[key] on a missing key → KeyError. Use dict.get(key, default) for safe access.
- Sets are unordered — don't rely on insertion order. Use a list if order matters.
- {} creates an empty dict, not a set. Use set() for an empty set.
Week 8 — String Methods & Formatting
Strings are immutable sequences with a rich method library. Learn to slice, search, replace, split, join, and format text for real-world use.
1. String Basics
s = " Hello, World! "
print(s.upper()) # " HELLO, WORLD! "
print(s.lower()) # " hello, world! "
print(s.strip()) # "Hello, World!"
print(s.strip().replace("World", "Python"))
print(len(s)) # 18Strings are immutable — every method returns a new string; the original is unchanged.
2. Split & Join
csv = "Alice,Bob,Charlie,Diana"
names = csv.split(",") # list of strings
print(names) # ['Alice', 'Bob', ...]
joined = " | ".join(names)
print(joined) # Alice | Bob | Charlie | Diana3. String Formatting
name, score = "Alice", 92.5
# f-string (recommended)
print(f"{name} scored {score:.1f}")
# format()
print("{} scored {:.1f}".format(name, score))
# Width & alignment
print(f"{name:<10}|{score:>8.2f}") # left|right aligned4. Useful Methods
| Method | Example | Result |
|---|---|---|
| find(sub) | "hello".find("ll") | 2 |
| count(sub) | "banana".count("a") | 3 |
| startswith(s) | "hello".startswith("he") | True |
| endswith(s) | "hello".endswith("lo") | True |
| isdigit() | "123".isdigit() | True |
| isalpha() | "abc".isalpha() | True |
| zfill(n) | "42".zfill(5) | "00042" |
5. Common Mistakes
- Forgetting that strings are immutable: s.upper() doesn't change s — you must reassign: s = s.upper().
- split() with no argument splits on any whitespace and removes empty strings; split(' ') preserves them.
- "hello"[0] = 'H' → TypeError. Create a new string: 'H' + "hello"[1:].
Week 9 — Functions
Functions let you name and reuse blocks of logic. Learn def, return, default arguments, keyword arguments, and variable scope (LEGB rule).
1. Defining Functions
def greet(name):
"""Return a greeting string."""
return f"Hello, {name}!"
print(greet("Alice")) # Hello, Alice!
print(greet("Bob")) # Hello, Bob!Always write a docstring (triple-quoted string right after def) to document what the function does.
2. Return Values
def divide(a, b):
if b == 0:
return None, "Division by zero"
return a / b, None
result, error = divide(10, 2)
if error:
print(error)
else:
print(result) # 5.03. Arguments
def power(base, exp=2): # default argument
return base ** exp
print(power(3)) # 9 (exp defaults to 2)
print(power(3, 3)) # 27
print(power(exp=3, base=2)) # keyword arg: 84. Scope (LEGB)
Python looks up variable names in this order: Local → Enclosing → Global → Built-in.
x = 10 # global
def func():
x = 20 # local — does NOT change the global x
print(x) # 20
func()
print(x) # 10
# To modify global x inside a function:
def func2():
global x
x = 99
func2()
print(x) # 995. Common Mistakes
- A function without return returns None implicitly.
- Mutable default arguments (def f(lst=[])) are shared between calls — use def f(lst=None): lst = lst or [].
- Calling a function before defining it → NameError. Define first, call second.
Week 10 — Basic Capstone: CLI To-Do App
Combine everything from weeks 1–9 into a full command-line to-do application with add, list, complete, and delete commands. Optionally persist tasks to a JSON file.
1. Project Specification
- Commands: add <title>, list, done <id>, delete <id>, quit
- Each task: id (auto-increment), title, done (bool)
- Persist tasks in tasks.json on disk
- Show task count and completion stats on list
2. Architecture
- load_tasks() / save_tasks() — JSON file I/O
- add_task(tasks, title) — append new task dict
- list_tasks(tasks) — print numbered table
- mark_done(tasks, task_id) — find by id and set done=True
- delete_task(tasks, task_id) — filter out by id
- main() — REPL loop with command dispatch
3. Sample Session
Todo App — type 'help' for commands
> add Buy groceries
[1] added.
> add Write report
[2] added.
> list
ID Status Title
1 [ ] Buy groceries
2 [ ] Write report
> done 1
[1] marked as done.
> list
ID Status Title
1 [x] Buy groceries
2 [ ] Write report
Done: 1/2
> quit
Bye!4. Extension Challenges
- Add a priority field (high/medium/low) and sort by priority on list
- Add a due date field and highlight overdue tasks in red (colorama)
- Add search <keyword> command to filter tasks
💻 Examples
Run these examples and check the output yourself.
phonebook = {}
while True:
cmd = input("add/lookup/delete/quit: ").strip()
if cmd == "add":
name = input(" Name: ")
phone = input(" Phone: ")
phonebook[name] = phone
print(f" Saved {name}.")
elif cmd == "lookup":
name = input(" Name: ")
print(" ", phonebook.get(name, "Not found"))
elif cmd == "delete":
name = input(" Name: ")
phonebook.pop(name, None)
elif cmd == "quit":
break
text = input("Enter a sentence: ").lower()
words = text.split()
freq = {}
for w in words:
freq[w] = freq.get(w, 0) + 1
for word, count in sorted(freq.items(), key=lambda x: -x[1]):
print(f" {word}: {count}")
a = set("the cat sat on the mat".split())
b = set("the dog sat on the log".split())
print("Common words: ", a & b)
print("Unique to A: ", a - b)
print("All words: ", a | b)
Common words: {'the', 'on', 'sat'}
Unique to A: {'cat', 'mat'}
All words: {'the', 'on', 'sat', 'cat', 'mat', 'dog', 'log'}raw = " python is AWESOME! "
cleaned = raw.strip().lower()
print(cleaned)
print(cleaned.count("is"))
print(cleaned.replace("python", "coding"))
python is awesome!
1
coding is awesome!line = "Alice,25,Seoul,Developer"
fields = line.split(",")
labels = ["Name", "Age", "City", "Job"]
for label, value in zip(labels, fields):
print(f"{label:6}: {value}")
Name : Alice
Age : 25
City : Seoul
Job : Developerstudents = [("Alice", 95), ("Bob", 82), ("Charlie", 71)]
print(f"{'Name':<10} {'Score':>6}")
print("-" * 18)
for name, score in students:
print(f"{name:<10} {score:>6}")
Name Score
------------------
Alice 95
Bob 82
Charlie 71def add(a, b): return a + b
def sub(a, b): return a - b
def mul(a, b): return a * b
def div(a, b): return a / b if b else "Error: division by zero"
a = float(input("a: "))
b = float(input("b: "))
print(f" +: {add(a,b)}")
print(f" -: {sub(a,b)}")
print(f" *: {mul(a,b)}")
print(f" /: {div(a,b)}")
def mean(lst):
return sum(lst) / len(lst)
def variance(lst):
m = mean(lst)
return sum((x - m)**2 for x in lst) / len(lst)
def std_dev(lst):
return variance(lst) ** 0.5
data = [10, 20, 30, 40, 50]
print(f"Mean: {mean(data):.2f}")
print(f"Std Dev: {std_dev(data):.2f}")
Mean: 30.00
Std Dev: 14.14def factorial(n):
"""Return n! recursively."""
if n <= 1:
return 1
return n * factorial(n - 1)
for i in range(1, 8):
print(f"{i}! = {factorial(i)}")
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040import json, os
FILE = "tasks.json"
def load_tasks():
if os.path.exists(FILE):
with open(FILE) as f:
return json.load(f)
return []
def save_tasks(tasks):
with open(FILE, "w") as f:
json.dump(tasks, f, indent=2)
def add_task(tasks, title):
task_id = max((t["id"] for t in tasks), default=0) + 1
tasks.append({"id": task_id, "title": title, "done": False})
print(f" [{task_id}] added.")
def list_tasks(tasks):
if not tasks:
print(" No tasks.")
return
print(f" {'ID':<4} {'Status':<8} Title")
for t in tasks:
status = "[x]" if t["done"] else "[ ]"
print(f" {t['id']:<4} {status:<8} {t['title']}")
done = sum(1 for t in tasks if t["done"])
print(f" Done: {done}/{len(tasks)}")
def mark_done(tasks, task_id):
for t in tasks:
if t["id"] == task_id:
t["done"] = True
print(f" [{task_id}] marked as done.")
return
print(f" Task {task_id} not found.")
def delete_task(tasks, task_id):
orig = len(tasks)
tasks[:] = [t for t in tasks if t["id"] != task_id]
if len(tasks) < orig:
print(f" [{task_id}] deleted.")
else:
print(f" Task {task_id} not found.")
def main():
tasks = load_tasks()
print("Todo App — type 'help' for commands")
while True:
line = input("> ").strip()
if not line:
continue
parts = line.split(maxsplit=1)
cmd = parts[0].lower()
arg = parts[1] if len(parts) > 1 else ""
if cmd == "add":
if arg:
add_task(tasks, arg)
save_tasks(tasks)
else:
print(" Usage: add <title>")
elif cmd == "list":
list_tasks(tasks)
elif cmd == "done":
try:
mark_done(tasks, int(arg))
save_tasks(tasks)
except ValueError:
print(" Usage: done <id>")
elif cmd == "delete":
try:
delete_task(tasks, int(arg))
save_tasks(tasks)
except ValueError:
print(" Usage: delete <id>")
elif cmd in ("quit", "exit"):
print(" Bye!")
break
elif cmd == "help":
print(" Commands: add <title>, list, done <id>, delete <id>, quit")
else:
print(f" Unknown command: {cmd}")
if __name__ == "__main__":
main()
📝 Exercises
Try them yourself first, then open the solution to compare.
Student Grade Book
Goal: Store student names and scores in a dict; print average, highest, and lowest.
- Read N students from input
- Store in dict {name: score}
- Print average (2 decimal), top scorer, lowest scorer
▶Toggle solution
n = int(input("Students: "))
grades = {}
for _ in range(n):
name = input(" Name: ")
score = int(input(" Score: "))
grades[name] = score
avg = sum(grades.values()) / len(grades)
top = max(grades, key=grades.get)
low = min(grades, key=grades.get)
print(f"Average: {avg:.2f}")
print(f"Top: {top} ({grades[top]})")
print(f"Lowest: {low} ({grades[low]})")
Duplicate Detector
Goal: Find duplicate numbers in a list using a set.
- Read space-separated integers
- Use a set to track seen numbers
- Print duplicates in sorted order
Numbers: 3 5 2 3 7 5 9
Duplicates: [3, 5]▶Toggle solution
nums = list(map(int, input('Numbers: ').split()))
seen, dups = set(), set()
for n in nums:
if n in seen:
dups.add(n)
seen.add(n)
print('Duplicates:', sorted(dups))
Password Validator
Goal: Check if a password meets complexity requirements.
- Minimum 8 characters
- At least one digit (any char.isdigit())
- At least one uppercase letter
- Print each failed rule
Password: hello
Failed: too short
Failed: no digit
Failed: no uppercase▶Toggle solution
pw = input("Password: ")
if len(pw) < 8:
print("Failed: too short")
if not any(c.isdigit() for c in pw):
print("Failed: no digit")
if not any(c.isupper() for c in pw):
print("Failed: no uppercase")
if len(pw) >= 8 and any(c.isdigit() for c in pw) and any(c.isupper() for c in pw):
print("Password OK")
Word Reverser
Goal: Reverse each word in a sentence while keeping word order.
- Read a sentence from input
- Reverse each word individually
- Join with spaces and print
Input: Hello World Python
Output: olleH dlroW nohtyP▶Toggle solution
sentence = input('Input: ')
result = ' '.join(w[::-1] for w in sentence.split())
print('Output:', result)
Is Prime?
Goal: Write is_prime(n) that returns True if n is prime.
- Handle n < 2 → False
- Check divisors only up to sqrt(n)
- Test for n = 1, 2, 17, 100
▶Toggle solution
def is_prime(n):
if n < 2: return False
for i in range(2, int(n**0.5)+1):
if n % i == 0: return False
return True
for n in [1, 2, 17, 100]:
print(f'is_prime({n}) = {is_prime(n)}')
is_prime(1) = False
is_prime(2) = True
is_prime(17) = True
is_prime(100) = FalseCaesar Cipher
Goal: Write encrypt(text, shift) that shifts each letter by shift positions.
- Preserve case (upper/lower)
- Non-alpha characters pass through unchanged
- Write a matching decrypt(text, shift)
encrypt('Hello, World!', 3) → 'Khoor, Zruog!'▶Toggle solution
def encrypt(text, shift):
result = []
for c in text:
if c.isalpha():
base = ord('A') if c.isupper() else ord('a')
result.append(chr((ord(c) - base + shift) % 26 + base))
else:
result.append(c)
return ''.join(result)
def decrypt(text, shift):
return encrypt(text, -shift)
print(encrypt('Hello, World!', 3))
print(decrypt('Khoor, Zruog!', 3))
Khoor, Zruog!
Hello, World!Implement the base app
Goal: Implement the to-do app as described with add, list, done, delete, and quit.
- All 5 commands work correctly
- Tasks persist across runs (JSON file)
- Invalid input shows helpful error messages
- · add/list work — 30%
- · done/delete work — 30%
- · JSON persistence — 30%
- · Error handling — 10%
Add priority support
Goal: Extend the app with a priority field (high/medium/low).
- add command accepts optional priority: add <title> [--priority high]
- list sorts by priority: high → medium → low
- Priority shown in list output
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗Comments 0
No comments yet. Be the first.
Only members can comment.
Comments with ads, abuse, personal information or illegal content are hidden or removed. Comments are shown with your nickname. Privacy Policy