Objective & prerequisites
Build a ledger around validated records without unnecessary inheritance. Before starting: basic Python functions, dictionaries, loops, JSON and terminal use. Complete the earlier Git/API/testing workshops if these are unfamiliar. Download and extract the kit into a new practice folder, then open a terminal in the software-kit folder. Python 3.10+ is required; the reference uses only the standard library. Work with the supplied fictional data. These free companion lessons do not change protected course access or award progress or certificates.
python3 --version
python3 -m unittest discover -s tests -vUnderstand the concept
Composition means one object uses other objects: Ledger holds an ID-indexed dictionary of Order instances. It does not inherit from dict because an unrestricted dictionary interface could bypass duplicate and type checks. Every Ledger initializes its own dictionary inside __init__. A mutable class attribute would be shared across instances. The leading underscore in _orders is a convention, not access control. The public summary method returns a newly constructed result so a caller changing that result does not change the ledger. Validation should happen before mutation; a rejected duplicate must leave the original record and total intact.
Worked example
Two ledgers start empty. Adding F01 to the first leaves the second empty. Adding F01 again is rejected even if the amount differs. The original total remains 12000 cents. The implementation does not overwrite, deduplicate or merge conflicting records because those actions require a source-resolution rule. In production a larger batch import might need transaction semantics; this teaching function builds a new local ledger and returns it only when every row is valid.
from dch_orders import Ledger, Order
a, b = Ledger(), Ledger()
a.add(Order("A", "web", 100))
assert a.summary()["total_cents"] == 100
assert b.summary()["count"] == 0Try it yourself
Run test_separate_instances and test_duplicate_preserves_original. Construct two ledgers, change the dictionary returned by summary() and confirm that a later summary is unchanged. Sketch why a shared class-level dictionary would contaminate another analysis. Write your expected outcome before running your implementation. Keep the supplied solution unchanged so that you can compare your own reasoning with it.
Worked solution
Create self._orders = {} for each instance. Check the ID before assigning it. summary builds new totals every call, so modifying a returned summary does not alter Order objects or the internal index. Composition keeps the supported interface small; it does not prevent deliberately accessing a Python underscore attribute. That distinction matters when explaining maintainability versus security.
Knowledge check
Would making Ledger a subclass of dict automatically enforce unique-ID rejection?
Check and explain
No. Ordinary dictionary assignment overwrites an existing key. A focused composed interface makes the intended rejection rule easier to inspect and test.
Evidence & common mistakes
Record the exact command, Python version, observed output and one rejected input. Explain what each check establishes and what it leaves untested. Do not remove validation merely to obtain a passing result. A local passing suite is evidence for these fixtures, not proof of production readiness. Credit the teaching reference and distinguish your own changes. The kit includes an exercise worksheet, a separate worked-solutions document, an API contract, expected results and a capstone rubric.
Authoritative reference
— official reference for the underlying interface. Lesson prose and fictional order examples are original. The teaching HTTP service is loopback-only, stateless and not suitable for production or uploading as a running Aruba service. No cloud account, paid API or registration is required.
Try the activity before reading its reference. Keep your sources, commands and assumptions with your work. Companion activities are unsaved self-practice and do not award a certificate or change lesson progress.