Lecture 10: Inheritance 1 Introduction to Programming with Python
Lecture 10: Inheritance
1
Introduction to Programming
with Python
Object Oriented Programming
2
• Classes represent new data types
• Classes have attributes and methods
• Objects are instances of a class
• Design program by objects interaction
• Encapsulation
• Polymorphism
• Operator overloading
Last session
Defining Rational numbers:
• Attributes, methods, constructor
• Encapsulation
• Define operators as method
• Method overloading
• Polymorphism
• Automatic type conversion
• Fractions (already in Python)
Defining Operators• Why not use natural arithmetic operators?
• Operator precedence will be kept
• All operations are method calls
From the book Programming in Scala
Characteristics of the
Object-Oriented Paradigm
Today
6
• Inheritance
• Iterator design pattern
Use Case: CIA
U.S. Central Intelligence Agency (CIA) wishes
that you develop a system to manage its secret
agents over the world
You agreed...
7
CIA Requirements (I)
An agent has:
1. Name
2. Age
3. List of visas to enable travel
4. Current location (Headquarters as default)
The CIA wishes to send agents to places all over
the world, given that they can enter these countries
(if has visa).
That will be all..
8
Class agent - Design
• Attributes: name, age, visas list, location
• Default location: headquarters (HQ).
• Constructor: given name and age.
• Methods:
1. add_visa(self, country): add country to the list of
visas in case it is not already there.
2. send_to(self, country): check if agent can be sent
to country. If so, change location and return True.
Otherwise, return False.
3. __repr__(self)
Class Agent - Implementation
Using the class Agent
Is that all?
• Create an agent.
• Test representation string.
• Add visas.
• Send between countries.
• Send to and from HQ
Sending an agent to HQ is always valid!
Adding return to HQ
CIA Requirements (II)
Some agents are Special Agents:
• Special agents have a rank. (attribute)
• Special agents can be promoted. (method)
(Regular agents: no rank)
Solution 1: Dummy Attributes
• Add attribute rank to class Agent
• Assign dummy value (-1) for regular agents
• Verify rank validity before every access to it
For example:
def promote(self):
if self.rank < 0:
raise Exception("...")
self.rank += 1
15
Dummy Attributes
Pros
• Easy to implement
Cons
• Add code to check validity of rank
• What happens if more attributes are added?
• Bad design
Solution 2:
New Class with Duplicated Code
• Create a new class called SpecialAgent
1. Copy all code from Agent Class
2. Then:
• Add rank attribute
• Update __repr__ method
• Add promote method
Class Special Agent (1)
18
Special Agent Demo
19
Code Duplication
SpecialAgent class is almost an identical copy of
class Agent. Only 3 lines are added to support
the rank functionality.
Pros
• Very easy to implement
Cons
• Maybe the worst thing a programmer can do…
20
CIA Rejects
• Please change the word “now” to “currently”:>>> a = Agent(“Stan”, 30)
>>> a
Stan, 30
[]
Currently in: HQ
21
change
here
Encapsulation - Reminder
All implementation details are hidden inside the
class.
The CIA will not change the way they use the classes.
So, no problem. We just need to change Agent class and
update its __repr__ method.
Is it enough?
22
Testing New Agent __repr__ Method
>>> a = Agent(“Stan”, 40)
>>> a
Stan, 40
[]
Currently in: HQ
23
Code Duplication Problem
>>> sa = SpecialAgent(“Jonathan”, 40, 9)
>>> sa
Jonathan, 40
[]
Now in: HQ
Level: 9
24
Wrong!!
Code Duplication vs. Reuse
• Duplication : hard to maintain code
• Fixing bugs: in several places
• Adding new features: in several places
• Code reuse makes software development easier:
• Code is written once
• Bugs are fixed in one place only
• Features are added in one place
• Code is easier to understand
But:
how to accomplish
this with objects?
Class relationship: is-a
• A special agent is a specific type of an agent.
• A special agent is-an agent.
called: an is-a relationship
• Set of special agents is a subset of set of agents.
• Not all classes relate likewise:
• A car is not an agent
• A dolphin is not an agent (well, not always…) 26
class
extension
Implementation: Class Inheritance
Class B extends class A:
• Class B inherits from class A
• Class A is said to be a base class
• Class B is said to be a derived class
Inheritance is commonly used to reflect is-a
relationship between classes
B is a subtype of A.
Python Inheritance
class SpecialAgent(Agent):
pass
SpecialAgent is a derived class of Agent.
Base ClassDerived Class
addition:
“empty”
Code Reuse
A derived class inherits all attributes and methods
from its base class:
>>> sa = SpecialAgent("Jonathan", 40)
>>> sa
Jonathan, 40
[ ]
Now in: HQ
29
SpecialAgent
behaves
like an Agent
Overriding Methods
In order to add the rank attribute we redefine the
constructor __init__ in SpecialAgent class:
class SpecialAgent(Agent):def __init__(self, name, age, rank):
self.name = nameself.age = ageself.visas = []self.location = "HQ"self.rank = rank
The new implementation overrides the
constructor __init__ in class Agent.30
Code Reuse and Overriding
The init method is still a duplicated code!
We can solve that by an explicit call to the base
class init method, along with additional code that
is relevant only for the derived class.
31
Special Agent Constructor
32
Special
Agent
Code
Explicit
call to
Agent init
class SpecialAgent(Agent):
Adding functionality
Derived classes can have additional attributes and
methods that base classes do not have.
For example, the SpecialAgent class will have a
method to promote an agent.
33
Rules for Subclass Constructor
Do one of the following:
1. Use previous constructor
• Don’t write any code
• previous constructor used automatically
2. Write a new constructor calling the previous one
• then add fields, changes, etc.
or:
add methods
(no pass)
Rules for Inherited Methods
Always use inherited methods when possible
Important: principle of code re-use
Call for Agent’s
class methods
also:
shorter than
bad example
Special Agent Demo
36
works
as before
Class Diagram
37
name: stringage: integer
visas: list of stringlocation: string
Agent
add_visa()
send_to()
rank: integer
SpecialAgent
promote()
Remember Polymorphism?
class Cat:
def talk(self):
return 'Meow!'
class Dog:
def talk(self):
return 'Woof! Woof!'
animals = [Cat(), Dog(), Cat()]
for anim in animals:
print(anim.talk())
Polymorphism Revisited
• All agents (including special) can be treated
the same way:
__repr__ method
overrides
inherited one
CIA Requirements (III)
• Some agents are Restricted Agents.
• Cannot have more than 5 visas
• How should we add this functionality?
Certainly, not by re-writing the class!!
40
Overriding: Different Behavior
Overriding can be used also to modify class
behavior or to change it completely
• rather than just to adding to it
still use
Agent’s method
Overriding: Example
Class Diagram
43
name: stringage: integer
visas: list of stringlocation: string
Agent
add_visa()
send_to()
rank: integer
SpecialAgent
promote()
RestrictedAgent
add_visa (override)
CIA Requirements (IV)
• Establish a task force of agents
• Several agent types can be in one task force
• All task force agents receive visas together
• All task force agents are sent together
44
Polymorphism:
The TaskForce Class
Special Agent Bond
send_to(state)
Special Agent English
send_to(state)
Agent Deadpool
send_to(state)
Restr. Agent Jason
send_to(state)
Task Force Class
All agent types have
send_to method
Using the TaskForce Class
CIA Requirements (V)
Given a TaskForce object, enumerate all agents
in a reverse manner
48
Solution: Do It On your Own!
• A CIA operator can always write this code:
49
But this is wrong!
• Encapsulation principle is violated
• What if we want to change implementation?
• Change the name of the list
• Map agent names to agent objects (instead of a list)
• Not easy for the user
50
Iterator Design Pattern
A Design Pattern is a general reusable solution
to a commonly occurring problem (Wikipedia).
The Iterator Design Pattern problem provides a
way to sequentially go over the elements of a
container, without exposing implementation
details.
51
Iterator Components
• Define an __iter__() method
• __iter__() returns object with a next method
• next iterates over the elements of the container
52
it = t.__iter__()
while true:
try:
i = it.next()
iteration block
except StopIteration:
break
What happens inside a for loop?
53
returns the next item each iteration
when StopIteration is raised, we know there
are no more items to iterator over, so we
terminate the loop with break
for i in t:
iteration block How does the
for loop work?
t is iterable.
__iter__() returns an iterator object
Iterable Task Force Class
54
Iterable Task Force Demo
55
Bug in Iteration
56
Where is a4?
Iterable Task Force Class
57
isinstance and issubclass• isinstance checks the type of an instance
• issubclass checks class inheritance
>>> a = Agent(“Ted”, 13)
>>> isinstance(a, Agent)
True
>>> isinstance(a, SpecialAgent)
False
>>> sa = SpecialAgent(“Omar”, 22, 20)
>>> isinstance(sa, Agent)
True
>>> isinstance(sa, SpecialAgent)
True
>>> isinstance(sa, RestrictedAgent)
False
>>> issubclass(SpecialAgent, Agent)
True 58
issubclass
Protecting the TaskForce
option 1:
continue…
Protecting the TaskForce – Option2
option 2:
more strict