PCPP1 study materials
PCPP1 study resources

PCPP1: Advanced Object-Oriented Programming

PCPP1 · Work through your exam, one topic at a time.

All guide sections

Advanced Object-Oriented Programming

Advanced OOP is the heaviest PCPP1 domain and almost entirely code-reading: you get a short snippet - a diamond hierarchy, a property with no setter, a class defining __eq__ - and must state what Python does at runtime. Marks go to candidates who know the object model's real rules, not the textbook UML version.

Special methods

  • __str__ is for users, __repr__ for developers; print() falls back to __repr__ when __str__ is missing, never the reverse.
  • Defining __eq__ sets __hash__ to None unless you define __hash__ too, so instances silently become unhashable.
  • functools.total_ordering fills in the remaining comparisons from __eq__ plus one of __lt__, __le__, __gt__, __ge__.

Inheritance and super()

  • C3 linearisation: with A as base of both B and C, class D(B, C) gives the MRO D → B → C → A → object.
  • Bare super() moves to the next class in the MRO, not to "the parent" - that is what makes diamonds work.

Class-level tools

  • abc.ABC plus @abstractmethod raises TypeError at instantiation, not when the subclass is defined.
  • @x.setter must reuse the getter's name and be defined after it; @classmethod takes cls and is the idiomatic alternative constructor; __slots__ removes the instance __dict__.

Worked example

class A:
    def ping(self): return 'A'
class B(A):
    def ping(self): return 'B' + super().ping()
class C(A):
    def ping(self): return 'C' + super().ping()
class D(B, C):
    def ping(self): return 'D' + super().ping()
print(D().ping())   # 'DBCA'

Reasoning: each ping prepends its letter and delegates through super(), so control flows D→B→C→A and the string builds back outwards. If C.ping had called A.ping(self) directly, A would run twice and the diamond would break.

Traps

  • Mutable class attributes are shared: self.items.append(x) mutates the class-level list; only rebinding creates an instance attribute.
  • isinstance(True, int) is True because bool subclasses int; copy.copy shares nested objects, copy.deepcopy does not.