ICS H32 Fall 2025
Exercise Set 6 Solutions
What's here?
These are solutions to a set of exercises, along with a fair amount of additional background explanation. Note that I've gone into more detail with those explanations that we would have wanted or expected students to do, but I'm using these as an opportunity to solidify your understanding; don't take this as an indication that you should be writing your answers in as much detail as I am here.
Problem 1
Course objects are mutable, because it's possible to add a new Student by calling add_student, which doesn't build a brand-new Course, but instead modifies the Course that's already there.__init__ method directly into an attribute, the mutability of the list doesn't change. The caller of the function will still have its reference to this list after the __init__ method ends — when we pass an argument to a function, it's more like a loan than a gift — which means that code outside of the Course class can now modify that list and, in so doing, modify the list of students enrolled in the course. The way to mitigate that risk would be to copy a separate list into an attribute instead:
self._students = students[:]
That choice gives up some time — copying the list will take time proportional to how long the list is — but gets back a hardened guarantee that the list of students within a Course object can't be modified outside of it, as long as the rest of the program respects the fact that we've marked the attribute as protected.
return self._students[:]
As we learn more Python, we'll have more choices here, as well. For example, rather than returning a list, we could instead return a generator, which means that our method would return an object capable of telling its caller, one at a time, what objects are in the list, without giving the caller access to the list itself.Problem 3
There are an enormous number of ways to solve this problem, ultimately, because we gave you the freedom to attack this in whatever way you believed was the right one. One possible solution is below, but there are certainly many, many other ways to accomplish the same goals.
I went ahead and did a few things that we haven't seen before in Python, particularly involving the generation of random values (e.g., students needed random names, so I generated them), unit tests that expect exceptions to occur, as well as a custom exception type that carries an error message.
Problem 4
If all you're working on is one program, it can be difficult to see the benefits of virtual environments, because the problem they solve is allowing your work on one program to be fully isolated from your work on another. A virtual environment is a complete Python installation — a Python shell, the standard library, and so on — as well as a collection of third-party libraries. At first, that sounds like a solution in search of a problem; why do I want a separate installation of Python if I've already installed Python on my machine?
Where we can get into trouble without a virtual environment is when we want to work on more than one program, but those programs have requirements that are incompatible with one another. For example, one of your programs might require an older version of a third-party library, while another of your programs might require a newer version. One of your programs might require a third-party library that's incompatible with a different library required by another of your programs. You might want to upgrade a library while working on one of your programs, but that would require you to update another of your programs, as well.
Virtual environments remove all of this friction between the needs of many programs that you're writing simultaneously. While that sounds hypothetical — and, in this course, it might really be hypothetical, ultimately — it's a very real problem, even for hobbyist work. Once you start building a variety of programs that use a variety of third-party libraries, you'll run into a problem that virtual environments solve. Better to learn the tools to manage that complexity now, so that you don't get bitten by these kinds of problems later.
(There's also value in learning as many of the same tools as professionals use, even if you can't learn about all of them at once, because the sooner you understand how "real-world" programming is done, the sooner you'll be able to participate in it.)