0%

Inheritance and Polymorphism · practice

Use Optional Object Capabilities

A protocol says what every must provide. Sometimes one object can offer something extra without making it a requirement for all.

A choice question may explain its answer. A survey item has nothing useful to explain.

Ask whether a capability exists

Python’s hasattr(object, name) reports whether an attribute or is available:

Try it

A report can use the capability when present:

if hasattr(item, "explain"):
    lines.append(item.explain())

It still does not ask whether the object is a ChoiceQuestion. A future type can provide explain and receive the same treatment automatically.

Why check for explain rather than checking for ChoiceQuestion?

Keep the core contract small

Optional capabilities are useful only around a solid required protocol. If is_correct were optional, the report could not fulfill its main job.

Use this distinction:

  • required behavior makes the object usable at all;

  • optional behavior enriches one use when available.

Do not scatter hasattr around to avoid designing a contract. Use it for genuinely optional additions whose absence has a clear, ordinary meaning.

The exercise starts with the working duck-typed report and adds one optional explanation without naming any concrete class.

Task

Give ChoiceQuestion an explain() returning its reason.

Update report(items, responses) so an item’s explanation appears on its own line immediately after that item’s outcome when, and only when, the provides explain.

Use hasattr; do not check for a concrete class. The required prompt, points, and is_correct protocol remains unchanged.