All A Level 3 50 min read 10 question quiz 19 exam marks

Object-Oriented Design

Class and instance attributes, access levels, abstract classes and overriding, then the A Level design questions: composition against inheritance, association and aggregation, and reading and drawing UML class diagrams.

Class members and access levels

You have already built classes with a constructor, methods and properties. The A Level specification asks for the vocabulary and the precision on top of that.

Instance and class attributes

An instance attribute belongs to one object, and every object has its own copy. A class attribute belongs to the class itself and is shared by all its objects.

Python
class Student:
    school = "MskProd Academy"         # class attribute: one copy, shared
    count = 0

    def __init__(self, name):
        self.name = name               # instance attribute: one per object
        Student.count += 1

    @classmethod
    def from_text(cls, text):          # an alternative way to construct an object
        name, year = text.split(",")
        student = cls(name)
        student.year = int(year)
        return student

    @staticmethod
    def valid_year(year):              # belongs with the class but needs no object
        return 7 <= year <= 13

a = Student("Asha")
b = Student.from_text("Ben,11")
print(Student.count, a.school, b.year, Student.valid_year(14))
Kind of methodFirst parameterCan use
Instance methodself, the objectthe object's attributes and the class's
Class method, @classmethodcls, the classclass attributes, and can build new objects
Static method, @staticmethodnonenothing of the object or class: a plain function filed with the class

Access levels

Some languages enforce who can see an attribute. Python trusts the programmer and relies on naming conventions:

LevelPythonMeaning
PublicnamePart of the class's interface. Use it freely
Protected_nameFor the class and its subclasses. Please leave it alone
Private__namePython renames it to _Class__name to avoid accidents
Python
class Account:
    def __init__(self, owner):
        self.owner = owner
        self._balance = 0
        self.__pin = "4821"

acct = Account("Asha")
print(acct.owner, acct._balance)
print(hasattr(acct, "__pin"), hasattr(acct, "_Account__pin"))     # False True

The private attribute is not hidden, only renamed. It stops accidental access, not a determined programmer, and that is why exam answers should say the intent of encapsulation, not claim Python makes the data unreachable.

Making objects behave like built in types

Special methods let your own class work with len, for loops, indexing and sorting.

Python
class Playlist:
    def __init__(self, name):
        self.name = name
        self._songs = []

    def add(self, song):
        self._songs.append(song)

    def __len__(self):
        return len(self._songs)

    def __iter__(self):
        return iter(self._songs)

    def __getitem__(self, index):
        return self._songs[index]

    def __repr__(self):
        return "Playlist(" + repr(self.name) + ", " + str(len(self)) + " songs)"

p = Playlist("Revision")
p.add("Lofi 1")
p.add("Lofi 2")
print(len(p), p[0], list(p))
print(p)

class Card:
    def __init__(self, rank):
        self.rank = rank
    def __lt__(self, other):
        return self.rank < other.rank
    def __repr__(self):
        return "Card(" + str(self.rank) + ")"

print(sorted([Card(9), Card(2), Card(5)]))

__lt__ is all sorted needs to put your own objects in order. That is polymorphism at its most practical: sorted does not know what a Card is, and does not need to.

Inheritance, overriding and abstract classes

Inheritance lets a class take on the attributes and methods of another. The new class is the subclass (or child, or derived class) and the one it inherits from is the superclass (parent, or base class). It models an is-a relationship: a Circle is a Shape.

A subclass can override a method, supplying its own version, and it can call the original with super().

Python
class Employee:
    def __init__(self, name, base):
        self.name = name
        self.base = base

    def pay(self):
        return self.base

class Manager(Employee):
    def __init__(self, name, base, bonus):
        super().__init__(name, base)       # let the superclass set up its part
        self.bonus = bonus

    def pay(self):                         # overrides Employee.pay
        return super().pay() + self.bonus

staff = [Employee("Asha", 2000), Manager("Ben", 3000, 500)]
for person in staff:
    print(person.name, person.pay())

The loop calls pay() on each object and each gives its own answer. The caller does not check which kind of employee it has. That is polymorphism: the same message, different behaviour, decided by the class of the object.

Abstract classes

Sometimes a superclass exists only to say what every subclass must be able to do. An abstract class has at least one abstract method, with no body, which every concrete subclass has to supply. You cannot create an object from the abstract class itself.

Python
from abc import ABC, abstractmethod

class Shape(ABC):
    def __init__(self, name):
        self.name = name

    @abstractmethod
    def area(self):
        pass

    def describe(self):
        return self.name + " with area " + str(round(self.area(), 2))

class Rectangle(Shape):
    def __init__(self, w, h):
        super().__init__("Rectangle")
        self.w = w
        self.h = h

    def area(self):
        return self.w * self.h

class Circle(Shape):
    def __init__(self, r):
        super().__init__("Circle")
        self.r = r

    def area(self):
        return 3.14159 * self.r ** 2

for shape in [Rectangle(3, 4), Circle(2)]:
    print(shape.describe())

describe is written once, in Shape, and calls self.area(). It works for any shape, including ones that do not exist yet. Trying to build the abstract class itself fails:

Python
# raises: TypeError
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

shape = Shape()
An abstract class is a contract

It does not say how each shape calculates its area, only that every shape must. Code that is written against Shape never needs to change when a Triangle is added.

Dog and Cat inheriting from Animal, showing what is inherited, overridden and newA UML diagram of inheritance. The parent class Animal has the attributes name and age and the methods speak and describe. Two child classes, Dog and Cat, inherit from it, shown by lines ending in a hollow triangle pointing at Animal. Dog inherits name, age and describe unchanged, and overrides speak to return Woof. Cat inherits name and age, adds a new attribute, indoor, overrides speak to return Meow, and overrides describe while still calling the parent's version with super. A key says grey lines are inherited, coral lines are overridden and green lines are new in the subclass.Animalnameagespeak()describe()Dognameagedescribe()speak() -> 'Woof'Catnameageindoorspeak() -> 'Meow'describe() + super()inherits frominherited: used as it isoverridden: its own versionnew: only in this subclass1234
  1. The parent class holds what all animals share.
  2. Dog inherits everything and overrides speak.
  3. Cat adds an attribute of its own and overrides speak and describe.
  4. Inherited lines are used as they are, overridden lines replace the parent's version, and new lines exist only in the subclass.
Inheritance removes duplication: put shared behaviour in the parent, and only what differs in the children.

Composition, aggregation and association

Inheritance is the relationship people reach for first and the one they most often misuse. There are three others, and all of them are has-a or uses-a relationships rather than is-a.

RelationshipMeaningTestExample
AssociationOne object uses anotherCan the two exist with no lasting link?A Teacher marks a Student's work
AggregationThe whole has parts that can exist without itIf the whole is deleted, do the parts live on?A Team has Players
CompositionThe whole owns parts that cannot exist without itIf the whole is deleted, do the parts go too?A Car has an Engine
Python
class Engine:
    def __init__(self, horsepower):
        self.horsepower = horsepower

class Car:
    def __init__(self, horsepower):
        self.engine = Engine(horsepower)      # composition: the car creates and owns it

class Team:
    def __init__(self, players):
        self.players = players                # aggregation: they were created elsewhere

class Teacher:
    def mark(self, student):                  # association: uses the student for a moment
        return student + " marked"

car = Car(150)
players = ["Asha", "Ben"]
team = Team(players)
del team
print(car.engine.horsepower, players)         # the players outlive the team
print(Teacher().mark("Asha"))

Favour composition over inheritance

Inheritance locks the relationship in at the moment the class is written. Here is the standard trap:

Python
class Bird:
    def fly(self):
        return "flap flap"

class Penguin(Bird):
    pass

print(Penguin().fly())     # flap flap, but penguins cannot fly

A Penguin is a Bird, so it inherits fly. The model has gone wrong, and every new kind of bird that cannot fly makes it worse. Composition fixes it by treating the behaviour as a part, which the bird has:

Python
class Flies:
    def move(self):
        return "flaps"

class Walks:
    def move(self):
        return "waddles"

class Bird:
    def __init__(self, name, movement):
        self.name = name
        self.movement = movement          # has-a: how it moves is a part

    def move(self):
        return self.name + " " + self.movement.move()

for bird in [Bird("Sparrow", Flies()), Bird("Penguin", Walks())]:
    print(bird.move())

A new way of moving, swimming perhaps, is one new small class, and no existing class changes. The bird's behaviour could even be swapped while the program runs.

Design principles to quote

PrincipleIn practice
Encapsulate what variesPut the part that changes, such as how a bird moves, in its own class
Program to an interfaceWrite code against the abstract class, not against one concrete subclass
Favour composition over inheritanceUse is-a only where it is really true for the whole life of the object
Single responsibilityA class should have one reason to change
Four relationships between classes: inheritance, composition, aggregation and associationFour ways classes relate, drawn as UML. Inheritance means is a: Dog is an Animal, drawn with a hollow triangle pointing at the parent. Composition means owns: a Car has an Engine and the engine goes when the car goes, drawn with a filled diamond on the owner. Aggregation means has: a Team has Players, who exist without the team, drawn with a hollow diamond. Association means uses: a Teacher knows about a Class, drawn as a plain line or arrow.Inheritance: is a1AnimalDogDog is an AnimalComposition: owns2CarEngine11a Car has an Engine, and it goes whenthe car goesAggregation: has3TeamPlayer1*a Team has Players, who exist without itAssociation: uses4TeacherClass1*a Teacher knows about a Class
  1. Inheritance: a subclass is a kind of its parent.
  2. Composition: the whole owns its parts. If the whole goes, the parts go too.
  3. Aggregation: the whole has parts that can exist on their own.
  4. Association: one class knows about, or uses, another.
Ask two questions: is it a kind of that thing (inheritance), or does it have one (composition, aggregation)? If it has one, would the part survive without it?

UML class diagrams

The Unified Modelling Language draws a design before any code is written. A class is a box with three compartments: the name, the attributes and the methods. A symbol in front of each says who can use it.

A UML class diagramA UML class diagram. An abstract class Shape has a protected attribute name and the public methods area and describe. Two classes, Circle, with a private radius, and Rectangle, with a private width and height, each inherit from Shape, shown by a hollow triangle at Shape's end of the line, and each has its own area method. Below are the three other relationships. Composition, a filled diamond, joins Car to Engine because the car owns its engine. Aggregation, a hollow diamond, joins Team to Player because the players exist without the team. Association, a plain arrow, joins Teacher to Student because one uses the other.Inheritance, drawn as a UML class diagram«abstract»Shape# name: str+ area(): float+ describe(): strCircle- radius: float+ area(): floatRectangle- width: float- height: float+ area(): floatis aCarEngineCompositionthe car owns its engineTeamPlayerAggregationplayers exist without the teamTeacherStudentAssociationone uses the other
A plus is public, a minus is private and a hash is protected.
SymbolMeans
+public
-private
#protected

The lines between classes carry the meaning:

LineRelationship
Solid line with a hollow triangle at the parent endInheritance: is-a
Solid line with a filled diamond at the wholeComposition: owns, and the parts die with it
Solid line with a hollow diamond at the wholeAggregation: has, and the parts live on
Plain solid line, often with an arrowAssociation: uses

Translating the diagram into code is mechanical. Each box is a class, each - attribute becomes self.__name or self._name, each arrow of inheritance becomes a class that names its parent in brackets, and each diamond becomes an attribute that holds another object.

Python
from abc import ABC, abstractmethod

class Shape(ABC):
    def __init__(self, name):
        self._name = name                  # protected: subclasses use it

    @abstractmethod
    def area(self):                        # + area(): float
        pass

    def get_name(self):
        return self._name

class Circle(Shape):
    def __init__(self, radius):
        super().__init__("Circle")
        self.__radius = radius             # private: only Circle touches it

    def area(self):
        return round(3.14159 * self.__radius ** 2, 2)

c = Circle(2)
print(c.get_name(), c.area())              # Circle 12.57
Read the arrow before the box

Questions give a UML diagram and ask for code, or give code and ask for the diagram. Mark each line as inheritance, composition, aggregation or association before you write anything, then write the classes. Most lost marks are an arrow pointing the wrong way or a private attribute written as public.

Key terms you must be able to define

Class attribute
An attribute that belongs to the class itself and is shared by every object of that class.
Instance attribute
An attribute that belongs to one object, so each object has its own copy.
Encapsulation
Bundling data with the methods that act on it, and restricting direct access to the data from outside the class.
Inheritance
A mechanism by which a subclass acquires the attributes and methods of a superclass.
Overriding
Providing a new version of an inherited method in a subclass.
Polymorphism
The ability for the same method call to behave differently depending on the class of the object it is called on.
Abstract class
A class that cannot be instantiated, which declares methods that its subclasses must implement.
Composition
A relationship in which one object is made of other objects that it owns, and which cannot exist without it.
Aggregation
A relationship in which one object holds other objects that can exist independently of it.
Association
A relationship in which one object uses another.
UML class diagram
A diagram that shows classes, their attributes and methods, and the relationships between them.

Flashcards

Say the definition out loud before you flip the card. Retrieving it from memory is what builds recall, reading it again is not.

DefineClass attribute
AnswerAn attribute that belongs to the class itself and is shared by every object of that class.
DefineInstance attribute
AnswerAn attribute that belongs to one object, so each object has its own copy.
DefineEncapsulation
AnswerBundling data with the methods that act on it, and restricting direct access to the data from outside the class.
DefineInheritance
AnswerA mechanism by which a subclass acquires the attributes and methods of a superclass.
DefineOverriding
AnswerProviding a new version of an inherited method in a subclass.
DefinePolymorphism
AnswerThe ability for the same method call to behave differently depending on the class of the object it is called on.
DefineAbstract class
AnswerA class that cannot be instantiated, which declares methods that its subclasses must implement.
DefineComposition
AnswerA relationship in which one object is made of other objects that it owns, and which cannot exist without it.

Reach the top grade on this topic

Object oriented answers reward exact vocabulary tied to the code in front of you.

  • Define encapsulation, inheritance and polymorphism separately, then show each in the given code
  • Say whether a relationship is is-a, or has-a, and name it: inheritance, composition or aggregation
  • Use the correct UML symbols for public, private and protected, and draw the arrow for inheritance towards the parent
  • In a design question, justify a choice: composition because behaviour might change, inheritance because it is truly is-a
  • Write super().__init__ in a subclass constructor, and mark abstract methods as abstract

Mistakes that cost marks here

Avoid these
  • Using inheritance for a has-a relationship, such as making Car a subclass of Engine.
  • Saying a private attribute in Python cannot be accessed at all, when it is only renamed.
  • Drawing the inheritance arrow towards the subclass instead of the superclass.
  • Forgetting to call super().__init__ in the subclass, so the inherited attributes are never set.
  • Mixing up class attributes, shared by all, and instance attributes, one per object.
Fun fact

Alan Kay, who coined the term object-oriented in the 1960s, later said he had in mind something closer to cells that send each other messages than to the class hierarchies most people now call OOP. The big idea, he said, was messaging.

Knowledge check

0 of 10 answered
1What is the difference between a class attribute and an instance attribute?
2What does super().__init__(name, base) do in a subclass constructor?
3What happens when you try to create an object from an abstract class?
4Which relationship does class Car having an Engine object that it creates and owns describe?
5What is polymorphism?
6In a UML class diagram, what does a - in front of an attribute mean?
7Which line in a UML diagram means inheritance?
8What does _balance with one leading underscore indicate in Python?
9Why is it often better to favour composition over inheritance?
10What does a @staticmethod have access to?
Score 0 / 10

Exam-style questions

Five written questions in the style of the real paper. Write a full answer, then let the marker check it against the mark scheme.

19 marks
1Explain what is meant by encapsulation, and give one benefit of using it.3 marks
Explain

Mark scheme0 / 3
  • LData and the methods that work on it are combined in one class
  • LAccess to the data from outside the class is restricted, for example by making attributes private
  • LBenefit: the data can only be changed through methods that check it is valid, so it stays consistent
Model answer

Encapsulation means that the data of an object and the methods that operate on it are combined in a single class, and access to the data from outside is restricted, usually by making the attributes private and providing methods to read or change them. The benefit is that the data can only be changed through methods that can check it is valid, so an object cannot be put into an inconsistent state by other parts of the program.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
2Explain the difference between a class and an object, using an example.3 marks
Explain

Mark scheme0 / 3
  • LA class is a template or blueprint that defines attributes and methods
  • LAn object is an instance of a class, created from it
  • LAn example, such as Dog as a class and rex as an object, where each object has its own attribute values
Model answer

A class is a template that defines the attributes and methods that its objects will have. An object is an instance of a class, created from that template, and it has its own values for the attributes. For example, a Dog class defines a name and a bark method, and rex and bella are two separate Dog objects, each with their own name.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
3A Vehicle class has a private attribute registration, a protected attribute speed that starts at 0, a method accelerate(amount) that increases the speed, and a method get_speed(). A subclass Lorry has an extra attribute load, and overrides accelerate so that the speed can never go above 60. Write Python class definitions for Vehicle and Lorry.6 marks
Write

Mark scheme0 / 6
  • LVehicle class with a constructor that sets registration as private and speed as 0
  • Laccelerate adds amount to speed
  • Lget_speed returns the speed
  • LLorry inherits from Vehicle
  • LLorry constructor calls super().__init__ and sets load
  • LLorry accelerate overrides, restricting the speed to a maximum of 60
Model answer
Python
class Vehicle:
    def __init__(self, registration):
        self.__registration = registration
        self._speed = 0

    def accelerate(self, amount):
        self._speed += amount

    def get_speed(self):
        return self._speed

class Lorry(Vehicle):
    def __init__(self, registration, load):
        super().__init__(registration)
        self.load = load

    def accelerate(self, amount):
        self._speed = min(self._speed + amount, 60)

truck = Lorry("AB12 CDE", 8000)
truck.accelerate(45)
truck.accelerate(45)
print(truck.get_speed())

Vehicle keeps registration private and speed protected, so the subclass can use it. Lorry inherits from Vehicle, calls the superclass constructor to set up the inherited attributes, and overrides accelerate so that the speed is capped at 60. The calls shown print 60.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
4Explain what is meant by polymorphism, using the shape classes in your answer as an example.3 marks
Explain

Mark scheme0 / 3
  • LThe same method name can be called on objects of different classes
  • LEach class provides its own version of the method, which overrides the one in the superclass
  • LThe version that runs depends on the class of the object, so area() gives a different calculation for a circle and a rectangle
Model answer

Polymorphism means that the same method can be called on objects of different classes and each responds in its own way. Each subclass provides its own version of the method, overriding the one in the superclass. For shapes, calling area() on a Circle object calculates pi times the radius squared and calling it on a Rectangle calculates width times height, and the program does not need to know which class it has because the object's class decides which version runs.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
5A game has a Character class. Some characters can fly, some can swim and some can do both. Discuss whether inheritance or composition is the better way to model how a character moves.4 marks
Discuss

Mark scheme0 / 4
  • LInheritance gives a fixed is-a hierarchy, and a character that can do both cannot easily inherit from two separate parents
  • LComposition lets each ability be a separate class held as a part
  • LNew abilities can be added or swapped without changing existing classes
  • LReasoned conclusion: composition is better because the abilities vary and combine
Model answer

Composition is the better choice. With inheritance, flying and swimming would each be a subclass, and a character that can do both would need to inherit from two parents or have a third class made for the combination, and every new ability would multiply the hierarchy. With composition each ability, such as Flying or Swimming, is its own class and a character holds the ones it has as attributes, so any combination is possible. A new ability can be added, or one swapped at run time, without changing any existing class, so composition suits behaviour that varies and combines.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
Machine mark 0 / 19