Classes II: Inheritance, Special Methods and Modules
Extend Rover with a new role, give shapes, money and cards useful interfaces, then build a real three-file shape report.
Contents
From the classroom to the lab
The expedition now uses inheritance for related roles and special methods for Python operations. Four short tasks practise those mechanisms. Finally, reuse the shape task to build a standalone area-report program.
Download starters and public tests ZIP · Open HW4 submission
Use Python 3.13 and the standard library. In each of the first four task folders, edit submission.py and run python -m pytest -q test_public.py. Install pytest with python -m pip install pytest if needed. The module project has its own three-file folder and packing script.
| Part | Tasks | Automatic | Staff |
|---|---|---|---|
| A | Shapes, Rover subclass, Money, Deck | 16 | 8 |
| B | Three-file shape report | 8 | 4 |
| C | Optional environment observation | 0 | 0 |
Week 10 totals 24 automatic + 12 staff points. HW4 covers weeks 10–12; use the submission page and course calendar for its deadline.
Each code entry is standalone. Retain the supplied helpers/base class and do not depend on code previously run in class. Annotate completed method interfaces; self needs no annotation. Tests call your interfaces; do not use input().
Part A · Classes and special methods
10-1 Shape family
Goal: let the same total_area() work with different shapes.
class Shape:
def area(self) -> float: ...
def name(self) -> str: ...
class Circle(Shape):
def __init__(self, r: float) -> None: ...
def area(self) -> float: ...
class Rectangle(Shape):
def __init__(self, w: float, h: float) -> None: ...
def area(self) -> float: ...
class Triangle(Shape):
def __init__(self, a: float, b: float, c: float) -> None: ...
def area(self) -> float: ...
def total_area(shapes: list[Shape]) -> float: ...
The starter supplies positive_dimensions(*values) for finite positive dimensions and triangle_area(a, b, c) for triangle validation and area. Both raise ValueError for invalid dimensions. Use these helpers directly; no formula derivation is required. Use math.pi for circles.
Shape.area()raisesNotImplementedError;name()returns the actual class name, such asCircle. The three subclasses store their own dimensions and overridearea().- Call the supplied helpers during construction to reject invalid dimensions, including degenerate triangles.
total_area()calls each object’sarea(). Return0for an empty list and preserve the input list and objects. New Shape subclasses must work without branching on class names.
items = [Circle(1), Rectangle(2, 3), Triangle(3, 4, 5)]
# [item.name() for item in items] -> ["Circle", "Rectangle", "Triangle"]
# total_area(items) -> math.pi + 12
Entry: w10-shapes, 4 automatic points. Numerical tests use moderate real values; no conversions for unrelated object types are required.
10-2 A new Rover role
Goal: reuse initialization and movement while adding survey records.
The starter fully supplies Rover(name, x=0, y=0). Each instance has name, x, y and an independent bag list. move(dx, dy) updates coordinates and collect(item) appends to the bag; both return None. report() returns a string such as "Ada @ (3, 4)".
Keep the base class and complete three methods:
class SurveyRover(Rover):
def __init__(self, name: str, x: int = 0, y: int = 0) -> None: ...
def record(self, sample: str) -> None: ...
def report(self) -> str: ...
- Initialize the inherited state through
super().__init__(), then create an independentsampleslist for each instance. record(sample)appends a string, allows duplicates and returnsNone. Samples and bag items are separate lists.- Extend
super().report()with" | samples: N", whereNis the sample count. Inheritmove()andcollect()without overriding them.
r = SurveyRover("Ada", 3, 4)
r.move(2, -1)
r.collect("apple")
r.record("rock")
# r.report() -> "Ada @ (5, 3) | samples: 1"
# r.bag -> ["apple"]; r.samples -> ["rock"]
Names, items and samples are strings; coordinates and offsets are integers. No map boundaries or additional game rules are required. Public tests temporarily replace base methods to check that the subclass reuses base initialization/reporting rather than copying their implementation.
Entry: w10-rover, 4 automatic points.
10-3 Money
Goal: support representation, arithmetic and comparison for money objects.
The supplied to_cents(yuan) validates and converts yuan into integer cents. For example, 1.005 becomes 101 and -1.005 becomes -101. It accepts finite int/float values with magnitude at most 10**9; otherwise it raises ValueError. Use this helper directly; implementing Decimal rounding is not part of this task.
class Money:
def __init__(self, yuan: float) -> None: ...
def __repr__(self) -> str: ...
def __add__(self, other: "Money") -> "Money": ...
def __sub__(self, other: "Money") -> "Money": ...
def __eq__(self, other: object) -> bool: ...
def __lt__(self, other: "Money") -> bool: ...
- Store
to_cents(yuan)inself._cents. Repr uses exactly two decimal places:Money(12.50),Money(-1.01),Money(0.00). - Addition/subtraction return new Money objects, preserving operands. Keep integer cents even for results beyond the constructor’s input bound. You can create
Money(0)and set the result’s_centswithout a floating-point conversion. - Equality and ordering compare cents. All four binary special methods return
NotImplementedfor non-Money operands so Python can handle the remaining protocol.
# Money(0.1) + Money(0.2) == Money(0.3) -> True
# repr(Money(10.5) - Money(0.25)) -> "Money(10.25)"
# Money(1) == object() -> False
# Money(1) + 1 -> TypeError
Entry: w10-money, 4 automatic points.
10-4 Deck
Goal: use a custom deck through Python’s container operations.
Construction and shuffle() are supplied; retain them. Each instance owns a self._cards list containing 52 unique rank+suit strings. Ranks are A/2/…/10/J/Q/K, grouped by suits C/D/H/S.
class Deck:
def __init__(self) -> None: ... # supplied
def __len__(self) -> int: ...
def __getitem__(self, i: int) -> str: ...
def __contains__(self, card: str) -> bool: ...
def shuffle(self) -> None: ... # supplied
def deal(self, n: int) -> list[str]: ...
- Length is the number of remaining cards. Support positive/negative integer indices and raise
IndexErrorout of bounds. Membership reports whether the card remains. deal(n)removesncards from the front and returns a separate new list. Require a nonnegative integer no larger than the remainder; otherwise raiseValueErrorwithout mutation. Zero returns an empty list.- Deck instances are independent. Raising
IndexErrorfor invalid indices also allows sequence-stylelist(deck); a separate__iter__()is unnecessary.
# deck = Deck(): len(deck) -> 52; deck[0] -> "AC"; deck[-1] -> "KS"
# deck.deal(2) -> ["AC", "2C"]; len(deck) -> 50; "AC" in deck -> False
The provided shuffle calls random.shuffle(self._cards) in place and returns None. Tests replace randomness with a known permutation to check delegation. Random algorithms are not assessed, and a changed order on every call is not required.
Entry: w10-deck, 4 automatic points.
A mechanisms and verification
Entry w10-a-notes has two responses worth 4 staff points each:
- Use your SurveyRover to explain which attributes
super().__init__()creates and howreport()extends base behavior. Give operations and actual results for two instances to check list sharing. - Choose an expression involving Money or Deck and explain its special method. Give one unsupported input or state-changing operation, expected/actual results and whether the original object changes.
A short explanation and a small example per response are sufficient; do not repeat every interface specification.
Part B · Three-file shape report
10-5 Separate modules and imports
Goal: reuse task 10-1 in a real multi-file report program.
The download’s module-project/ folder contains three project files and a supplied tool:
shapes.py # reuse task 10-1
report.py # format the report
main.py # run the demo
pack_submission.py # supplied packer
After completing it, python main.py must print:
Rectangle: 6.00
Triangle: 6.00
Total: 12.00
Interfaces:
shapes.py: reuse your completed first task without depending onsubmission.py.report.py: implementbuild_report(items: list[Shape]) -> list[str]. Produce one line per object in input order usingname()andarea(), with two decimal places. Add a Total line usingtotal_area(items)imported from shapes. Empty input returns["Total: 0.00"]. Return text without printing or changing inputs; new Shape subclasses must work too.main.py: implementrun_demo() -> None. CreateRectangle(2, 3)andTriangle(3, 4, 5)using the classes from shapes, callbuild_report()from report and print each returned line. Protect entry withif __name__ == "__main__":.
Importing any of the three modules must be silent and must not start the demo. Both import module and from module import name are allowed. Dependencies run from main → report → shapes, with main also using shapes’ constructors. Public tests temporarily replace the report function to verify real integration; printing a fixed answer cannot pass.
Submission workflow:
python main.py
python -c "import shapes, report, main"
python pack_submission.py
python -m pytest -q test_public.py
The second command produces no output. The packer generates submission.py, whose project_files() -> dict[str, str] returns exactly the three filenames and their sources. Paste the generated file’s contents into w10-module-project. Repack after each project edit; no manual source-string assembly is needed. Download the packer separately.
Only those three files are evaluated. Use the standard library without local-file reads, network access, input() or GUI windows. project_files() returns source without running the project.
Entry w10-module-project: 8 automatic points. Written entry w10-b-notes: 2 staff points for responsibilities and adding new shapes; 2 for actual direct-run/import commands, output and explanation.
Part C · Environment observation (optional)
Run inside the module project:
python -c "import sys; print(sys.executable)"
python -c "import shapes; print(shapes.__file__)"
Identify the interpreter and imported file. You may record observations in w10-c-tools or leave it blank without affecting completion or marks.
4. Solo assignment 2 launch
Solo assignment 2: five prime-counting methods opens this week and is separate from HW4. Use its submission page and the course calendar for the deadline. Read the task first; L11 continues the algorithm details.
Full solo assignment 2 requirements (also shown on its submission page)
Solo2 covers weeks 10/11 and is worth 5% of the course grade. Use its submission page for the configured deadline.
| Entry | Function | Required method |
|---|---|---|
w10-primes-brute | count_primes_brute(n: int) -> int | Try factors2 through candidate−1 |
w10-primes-sqrt | count_primes_sqrt(n: int) -> int | Stop at d²>candidate |
w10-primes-6k | count_primes_6k(n: int) -> int | Handle2/3, then6k±1 factors |
w10-primes-sieve | count_primes_sieve(n: int) -> int | Eratosthenes marking |
w10-primes-mr | count_primes_mr(n: int) -> int | Bounded-domain Miller–Rabin |
Count primes 0≤p<n for0≤n≤100000. Values≤2 return0; negative n raises ValueError. Larger inputs are not required. Examples: n=0/2→0, n=3→1, n=10→4. Return an integer without printing.
MR handles values below2,2/3 and other even values before bases2,3 on remaining odds. The known deterministic bound below1,373,653 covers candidates below100000. This is not a determinism claim for arbitrary integers. L11 and assignment material develop decomposition/modular exponentiation and the other algorithms; establish interfaces and evidence now rather than requiring untaught implementations immediately.
Each method entry carries16 automatic raw points. The staff report carries20;100 raw points normalize to this assignment’s5%. Tests primarily check results/edges; staff inspect sources and records for genuinely different methods. Do not wrap one algorithm five times. Each entry includes its helpers; pow(a,d,m) is allowed for MR.
w10-primes-report: method/source evidence6, boundary/cross-checking6, fair reproducible timing6, conclusions/limits2, declaration0. Verify correctness before timing. Slow methods may use smaller n rather than another algorithm. Record actual sizes, repetitions, environment, preparation/query accounting and counts; make at least three measurements, without claiming a single ratio is universal.
Submission checklist
- Submit four class tasks and the module project separately; complete the two short written cards with mechanisms and actual results.
- Repack after editing the project; direct execution prints a report and imports are silent.
- Complete HW4’s single AI-use declaration and submit the downloaded evaluation report.