CS61A(17): Inheritance

This is the lecture note of CS61A - Lecture 17.

Attribute Assignment

  • Instance attribute: attribute of an instance
  • Class attribute: attribute of the class of an instance

Attribute assignment statements change the values that are bound with an object or a class through attribute names.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Code Review

class Account:
interest = 0.02 # class attribute

def __init__(self, holder):
self.holder = holder
self.balance = 0

def deposit(self, amount):
"""Add amount to balance."""
self.balance = self.balance + amount
return self.balance

def withdraw(self, amount):
"""Subtract amount from balance if funds are available."""
if amount > self.balance:
return 'Insufficient funds'
self.balance = self.balance - amount
return self.balance

Inheritance

Base class attributes aren't copy into subclasses! Instead, it is a process of looking up an attribute by name.

  • If it names an attribute in the class, return the attribute value.
  • Otherwise, look up the name in the base class, if there is one.
1
2
3
4
ch = CheckingAccount('Tom') # Calls Account.__init__
ch.interest # Found in CheckingAccount
ch.deposit(20) # Found in Account
ch.withdraw(5) # Found in CheckingAccount

Object-Oriented Design

Design guidance:

  • Don't repeat yourself, use existing implementations
  • Attributes that have been overridden are still accessible via class objects
  • Look up attributes on instances whenever possible
  • Inheritance is best for representing is-a relationships:
    • Eg: a checking account is a specific type of account. So, CheckingAccount inherits from Account
  • Composition is best for representing has-a relationships:
    • composition: one object has another object as an attribute
    • Eg: a bank has a collection of bank accounts it manages. So, a bank has a list of accounts as an attribute
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# DEMO

class Bank:
"""A bank has accounts and pays interest.

>>> bank = Bank()
>>> john = bank.open_account('John', 10)
>>> jack = bank.open_account('Jack', 5, CheckingAccount)
>>> john.interest
0.02
>>> jack.interest
0.01
>>> john.interest = 0.06
>>> bank.pay_interest()
>>> john.balance
10.6
>>> jack.balance
5.05
>>> bank.too_big_to_fail()
True
"""
def __init__(self):
self.accounts = []

def open_account(self, holder, amount, account_type=Account):
"""Open an account_type for holder and deposit amount."""
account = account_type(holder)
account.deposit(amount)
self.accounts.append(account)
return account

def pay_interest(self):
"""Pay interest to all accounts."""
for account in self.accounts:
account.deposit(account.balance * account.interest)

def too_big_to_fail(self):
return len(self.accounts) > 1

Attributes Lookup Practice

There is a good example to check your understanding of looking up attributes.

🚀 LINK: Hint Video

Multiple Inheritance

Multiple inheritance is when a subclass has multiple base classes.

1
2
3
4
5
6
7
>>> such_a_deal = AsSeenOnTVAccount('John')
>>> such_a_deal.balance
1
>>> such_a_deal.deposit(20) # SavingsAccount method
19
>>> such_a_deal.withdraw(5) # CheckingAccount method
13