0%

Objects Working Together · practice

Hold a Collection of Objects

A single Question is not a quiz. A quiz is several of them, in an order somebody chose, with a title on the front.

You already know how to keep several things: a . What is new is that the list belongs to an , and that object decides what may be done with it.

A list inside a class

Try it

_questions is internal, for the reasons Chapter 5 gave. What the outside world gets instead is add, a count, and a total. Every one of those is about the quiz, not about the list.

Look at total_points. It over Question objects and asks each for its own points. The Quiz never learns how a question decides what it is worth, and would keep working if that became a computed property tomorrow.

Iterating a collection of objects

A loop over objects looks exactly like a loop over numbers. The difference is what you can do inside it:

Try it

That worked, and it reached straight past the class into _questions. In real code that line is a warning sign. If the outside world needs to walk the questions, the quiz should offer a way that does not depend on the collection being a list:

Try it

Chapter 11 gives a much better way to write this, by making the quiz itself something a for loop understands. For now a returning the questions is honest and enough.

Returning a copy, and why

questions() returns list(self._questions), not self._questions. That one call matters:

Try it

The caller removed an item from the list it was given, and the quiz still reports both questions. Return the internal list directly and that same pop() would have silently thrown away one of the quiz’s questions, through a that looked like a private copy.

This is the -list behavior from Fundamentals I, met again in a place where it does real damage. A method that hands out the object’s own list has undone everything the underscore was for.

Why does questions() return list(self._questions) rather than self._questions?

Note what list() does and does not protect. The new list is separate, so adding and removing cannot reach the quiz. The Question objects inside it are the same objects, so a caller could still change one of them. Chapter 8 comes back to that with values that cannot be changed at all.

The exercise

You are building the Quiz that the rest of the chapter uses. It holds questions, reports on them, and does not hand out the list that controls its membership. The copy still contains the same Question objects, exactly as the shallow-copy explanation above says.

Task

Finish the collection boundary of the supplied Quiz class.

add(question) appends a question and refuses None with a . questions() returns the questions in order in a new , so adding or removing from the returned list cannot change quiz membership.

question_at, question_count, total_points, and hardest are supplied so you can concentrate on the one new difficulty: owning a collection safely.

Run the program and confirm the final line is 3: removing an item from the list returned by questions() must leave the quiz with all three questions.