Course progress Course outline 24 of 24 lessons available
Python Foundations
Data and Collections
Building Reliable Programs
Modeling with Objects
Professional Python
Advanced Python
One loop, one job
Chapter 7 gave you boxes called lists, dictionaries, and sets. Now Python can walk past every box and do one small job.
- Take one Python gets a value
- Do the job your loop body runs
- Move on repeat until done
Ask for the value you need:
topics = ["Python", "Git", "SQL"]
for topic in topics:
print("Practice", topic)
If you also need a display number, use enumerate():
for number, topic in enumerate(topics, start=1):
print(number, topic)
Output:
1 Python
2 Git
3 SQL
start=1 changes the numbers made by enumerate(). It does not change the list or its real indexes. Use range(len(topics)) only when the numeric index itself is part of the job.
Match the two rows with zip()
Imagine two rows of cards. zip() clips the first cards together, then the second cards, and so on.
- Python 55 minutes
- Git 25 minutes
- SQL 40 minutes
topics = ["Python", "Git", "SQL"]
minutes = [55, 25, 40]
print(list(zip(topics, minutes)))
Output:
[('Python', 55), ('Git', 25), ('SQL', 40)]
There is one important edge: ordinary zip() stops at the shortest input.
print(list(zip(["Python", "Git", "SQL"], [55, 25])))
Output:
[('Python', 55), ('Git', 25)]
SQL quietly disappears. If that would mean broken data, use zip(topics, minutes, strict=True). Python 3.10 or newer then raises ValueError when the lengths differ. Chapter 10 will teach you how to handle that error.
Sort without messing up the shelf
sorted() makes a new list. The original stays put.
minutes = [55, 25, 40]
ranked = sorted(minutes, reverse=True)
print(ranked)
print(minutes)
Output:
[55, 40, 25]
[55, 25, 40]
Use a small key function when Python should compare one part of each record:
def minutes_in(record):
return record["minutes"]
records = [
{"topic": "Python", "minutes": 40},
{"topic": "Git", "minutes": 25},
{"topic": "SQL", "minutes": 40},
]
print([record["topic"] for record in sorted(records, key=minutes_in, reverse=True)])
Output:
['Python', 'SQL', 'Git']
Python’s sort is stable: Python and SQL tie, so they keep their earlier order. Pass the function as key=minutes_in, without ().
Short warning: minutes.sort() changes that list and returns None. Use sorted(minutes) when you want a new result and the old shelf must stay unchanged.
Comprehensions are tiny collection machines
- Old collection 20, 35, 50
- Optional filter keep 30 or more
- New collection 35, 50
minutes = [20, 35, 50]
long_sessions = [value for value in minutes if value >= 30]
topic_names = {name.strip().casefold() for name in [" Python ", "python", "Git"]}
lookup = {topic: value for topic, value in zip(["Python", "Git"], [20, 35])}
print(long_sessions)
print(sorted(topic_names))
print(lookup)
Output:
[35, 50]
['git', 'python']
{'Python': 20, 'Git': 35}
Square brackets make a list, braces with one expression make a set, and key: value makes a dictionary. A good comprehension has one obvious transformation and perhaps one simple filter. If you need several decisions, messages, or updates, open it into an ordinary loop. Easy to read beats short.
Build a study parade
Save this complete project as study_parade.py. It pairs the data strictly, sorts a new list, numbers the result, and checks that the source was not changed.
def make_records(topics, minutes):
return [
{"topic": topic, "minutes": duration}
for topic, duration in zip(topics, minutes, strict=True)
]
def minutes_in(record):
return record["minutes"]
def build_report(topics, minutes, target):
ranked = sorted(make_records(topics, minutes), key=minutes_in, reverse=True)
lines = []
for number, record in enumerate(ranked, start=1):
if record["minutes"] >= target:
status = "target met"
else:
status = "keep going"
lines.append(
f"{number}. {record['topic']}: "
f"{record['minutes']} minutes ({status})"
)
return lines
topics = ["Python", "Git", "SQL", "Testing"]
minutes = [55, 25, 40, 25]
topics_before = topics.copy()
report = build_report(topics, minutes, target=30)
assert topics == topics_before
assert report[0].startswith("1. Python")
print("Study parade")
for line in report:
print(line)
print("Source still:", topics)
Run python3 study_parade.py. You should see:
Study parade
1. Python: 55 minutes (target met)
2. SQL: 40 minutes (target met)
3. Git: 25 minutes (keep going)
4. Testing: 25 minutes (keep going)
Source still: ['Python', 'Git', 'SQL', 'Testing']
Git stays before Testing because they tie and sorting is stable. If an AssertionError appears, one of the promised facts is no longer true.
Three tiny missions
- Number four snack names with
enumerate(start=1). - Try ordinary
zip()with three names and two scores; then addstrict=Trueand note the error type. - Add a 60-minute session to the project, then use a comprehension to collect only topics that met the target.
Ready for Chapter 9?
- I can loop over values directly.
- I can add human-friendly numbers with
enumerate(). - I can explain why ordinary
zip()may drop an item. - I can use
sorted()without changing the source. - I can keep a comprehension simple and choose a loop when it grows crowded.
- I ran the Study Parade and saw every assertion pass.
Next, you will put these jobs into small cooperating functions and learn where each function can see its names.