Python Classes Quiz: Magic Methods, Properties and Dataclasses

Test your Python classes with 12 questions and three programs on self and attributes, magic methods, properties, class methods, dataclasses and class design.

  • Course: Python study plan
  • Module: Classes and objects
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 25 min
  • Runtime: CPython 3.11

Checkpoint — Classes and objects is the checkpoint that closes the Classes and objects module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint covers the whole module: the class statement with __init__, self, instance and class attributes, the dunder methods that make a class behave like a built-in, @property and the encapsulation conventions with __slots__, class methods as alternative constructors and static methods, dataclasses with their options and __post_init__, and the design discipline of invariants and small interfaces.

How it works. Twelve questions and three programs. You need 70% on the questions and every program accepted to clear the module. You can retake it as often as you like; your best score counts.

Before you start, make sure you can answer these from memory:

  • What does obj.method(x) become, and why is self the first parameter?
  • Why is members = [] in a class body a bug, and where does per-instance state belong?
  • What must __eq__ return for a foreign type, and what happens to __hash__ when __eq__ is defined?
  • Which dunders make len(x), x in c, for e in c and 3 * x work?
  • Why does a from_… class method call cls(...) rather than the class by name?
  • What does @dataclass(frozen=True) give you that the default does not?
  • Where does validation go in a dataclass, and in a hand-written class?

The three programs are a Fraction value type with arithmetic, comparison and hashing dunders, a bank ledger whose accounts enforce invariants and are built through class-method constructors, and a frozen dataclass catalogue with derived fields, sorting and replace.

Common questions

What does obj.method(x) become, and why is self the first parameter?

It becomes Class.method(obj, x): attribute lookup finds the function on the class and binds it to the instance, and the call passes that instance as the first argument. Every method therefore declares self first to receive it.

Which dunders make len(x), x in c, for e in c and 3 * x work?

__len__ for len(x), __contains__ for in, __iter__ for a for loop — __getitem__ alone also gives iteration — and __rmul__ for 3 * x, the reflected call Python tries after int.__mul__ returns NotImplemented.

What does @dataclass(frozen=True) give you that the default does not?

Immutability and hashing: assigning a field after construction raises FrozenInstanceError, and the generated __hash__ lets instances serve as dict keys and set members. A default dataclass is mutable and, because it defines __eq__, unhashable.

Exercises

A fraction value type

Implement Frac(num, den) normalised in __init__: reduce by the gcd and keep the sign in the numerator (a zero denominator raises ValueError). Define __add__, __sub__, __mul__, __truediv__ (division by a zero fraction raises ZeroDivisionError), __eq__, __lt__, __hash__ and __str__ (3/4, or just 2 when the denominator is 1). Evaluate lines a/b op c/d and print the result; print the exception name for a failure.

Input: lines. Output: one line per input line.

1/2 + 1/3
3/4 * 4/3
1/2 - 1/2
1/3 / 0/5

prints

5/6
1
0
ZeroDivisionError

Ledger

Implement Account with a class method from_line("ada:100"), a transfer(to, amount) method that raises ValueError when the balance is insufficient (checking before changing either account), and a class-level count of open accounts. Commands: open name:balance, transfer from to amount (prints ok, insufficient funds or unknown account), report (prints name balance in name order, then accounts <count>).

Input: commands. Output: one line per transfer, and the report lines.

open ada:100
open bob:20
transfer ada bob 30
transfer bob ada 500
transfer cy ada 1
report

prints

ok
insufficient funds
unknown account
ada 70
bob 50
accounts 2

Product catalogue

Define @dataclass(frozen=True, order=True) Product with fields name: str, price_cents: int, qty: int and a derived field value: int = field(init=False, compare=False) set in __post_init__ with object.__setattr__. Read n products; print them ordered by value descending then name (an explicit key), then the first product with its quantity increased by one via replace (the value must be recomputed automatically), then asdict of that copy as JSON with sorted keys.

Input: n, then n lines name price qty. Output: n lines name value, then the replaced product's repr, then the JSON.

2
bolt 5 100
nut 2 250

prints

bolt 500
nut 500
Product(name='bolt', price_cents=5, qty=101, value=505)
{"name": "bolt", "price_cents": 5, "qty": 101, "value": 505}

In this module: Classes and objects

← Designing a class — invariants, interfaces and a worked example · Inheritance basics — subclasses, super() and attribute lookup →