Lecture 15

Inheritance & Interfaces

July 18, 2017

  • Designing for Inheritance
  • Complications
  • Interfaces

Announcements

  • An opportunity for redemption
    • In discussion 8 Tue/Wed, Redemption Quiz 1 is optional
      • Turn it in at lecture Wed/Thu if you want feedback
    • In lab 9 Wed/Thu and lab 10 Mon/Tue, complete a
      Midterm Check-off for 3 midterm points
      • No regular lab check-off this week
    • In discussion 9 Thu/Fri, complete
      Redemption Quiz 2 for 3 midterm points
      • Full credit for good effort
    • Redeem 6 possible points up to max of 70 midterm points
  • Midterm "Review Sessions" with Stan (more info on Piazza)
  • Post-midterm advising sessions with the course staff

Objects

  • This week, the goals are:
    • To learn the paradigm of object-oriented programming
    • To study applications of, and problems that be solved using, OOP

Introduction

Data

Mutability

Objects

Interpreters

Paradigms

Applications

Functions

Terminology: Attributes, Functions, and Methods

All objects have attributes, which are name-value pairs

Classes are objects too, so they have attributes

Instance attribute: attribute of an instance

Class attribute: attribute of the class of an instance

Functions are objects

Bound methods are objects too: functions that provide self automatically

Dot expressions evaluate to bound methods for class attributes that are functions

Class

Attributes

Functions

Bound

Methods

Inheritance

Inheritance

Inheritance is a technique for relating classes together

Common use: a specialized class inherits from a general class

class <new class>(<base class>):

<suite>

  • New class shares (not copies) attributes from the base class
  • New class overrides certain inherited attributes with its own
  • Implementing the new class is now as simple as specifying how it's different from the base class

Inherited Attributes

Base class attributes are
not copied into subclasses!

Attribute Lookup in Classes

  • If the name is an attribute of the class, return its value
  • Otherwise, look up the name in the base class,
    if it exists

class CheckingAccount(Account):
interest
= 0.01
fee
= 1
def withdraw(self, amount):
total
= amount + self.fee
return Account.withdraw(
self, total)

>>> ch = CheckingAccount('Kevin')

>>> ch.interest

0.01

>>> ch.deposit(20)

20

>>> ch.withdraw(5)

14

CheckingAccount

Account

CheckingAccount

Demo

Object-Oriented Design

Designing for Inheritance

  • 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

class CheckingAccount(Account):
interest
= 0.01
fee
= 1
def withdraw(self, amount):
total
= amount + self.fee
return Account.withdraw(self, total)

Reuse code from base class

Preferred to CheckingAccount.fee

to allow for specialized accounts

An Energizing Example

Pokemon have:

  • a name
  • a trainer
  • a level
  • an amount of HP (life)
  • an attack: tackle

Pokemon can:

  • say their name
  • attack other Pokemon

Electric-type Pokemon have:

  • a name
  • a trainer
  • a level
  • an amount of HP (life)
  • an attack: thunder shock

Electric-type Pokemon can:

  • say their name
  • attack and sometimes paralyze other Pokemon

class Pokemon:
"""A Pokemon."""

class ElectricType(Pokemon):
"""An Electric-type Pokemon."""

Demo

  • Don’t repeat yourself! Use existing implementations
    • Pokemon.attack(self, other)
  • Reuse overridden attributes by accessing them through the base class
    • Pokemon.attack(self, other)
  • Look up attributes on instances if possible
    • self.prob

class ElectricType(Pokemon):

basic_attack = 'thunder shock'

prob = 0.1

def attack(self, other):

Pokemon.attack(self, other)

if random() < self.prob and type(other) != ElectricType:

other.paralyzed = True

print(other.name, 'is paralyzed!')

Multiple Inheritance

Multiple Inheritance

  • In Python, a class can inherit from multiple base classes
  • This exists in many but not all object-oriented languages (notable exception: Java)
  • This is a tricky and often dangerous subject, so tread carefully!

class FlyingType(Pokemon):

basic_attack = 'peck'

damage = 35

def fly(self, location):

print(self.trainer, 'flew to', location)

Zapdos

Zapdos is a legendary bird Pokemon

  • Zapdos' attack, thunder, does a lot of damage
  • Zapdos can paralyze when attacking
  • Zapdos can fly
  • Zapdos can't say its own name

class Zapdos(ElectricType, FlyingType):

basic_attack = 'thunder'

damage = 120

def speak(self):

print('EEEEEEEE')

Evaluating dot expressions

Pokemon

ElectricType

FlyingType

Zapdos

Demo

A Note on Design

  • This example is shortened for lecture and could be improved

  • We should create a class for every species of Pokemon
    • Consequently, we should not create instances of the Pokemon, ElectricType, or FlyingType classes

  • We should create classes for different types of attacks, with damage and special effect attributes
    • The relationship between classes that reference each other (e.g., Pokemon and Tackle) is called composition

  • Good design is a bigger topic in future classes

Complicated Inheritance

Biological inheritance

Gramma

Gramps

Grandpop

Grandmom

Mom

Dad

You

Aunt

some guy

Half

Half Cousin

some other guy

Double

Double

Double Half Uncle

Quadruple

Moral of the story

Inheritance can be complicated, so don't overuse it!

Break!

Interfaces

My late friend Alain Fournier once told me that he considered the lowest form of academic work to be taxonomy. And you know what? Type hierarchies are just taxonomy. You need to decide what piece goes in what box, every type's parent,
whether A inherits from B or B from A[...]

I believe that's a preposterous way to think about programming.
What matters isn't the ancestor relations between things but what they can do for you.

—Rob Pike, co-creator of the Go programming language

Interfaces

Programs often require communication between multiple components

  • Communication between the program and the user, between two different parts, between two objects in the same program...
  • This can get very complicated, since these components often have different behaviors and specifications
  • Inheritance is often the wrong tool for enabling communication between different parts of a program

Interfaces are a specification of the rules for communication

  • To use an object, we don’t need to know how it is implemented if we know the interface for the object: data abstraction!
  • Python has common interfaces called protocols

Python Protocols

Magic methods: special methods surrounded by double underscores that add "magic" to your classes

We will look at two examples of these interfaces:

  • The arithmetic interface
  • The (mutable) container protocol

s = Pokemon('Squirtle', 'Kevin')

b = Pokemon('Bulbasaur', 'Stan')

p = ElectricType('Pika', 'Stan')

def __init__(...)

len([s, b, p])

len({'Kevin': [s],
'Stan': [b, p]})

len('Bulbasaur fainted!')

def __len__(...)

Interface

Demo

Custom Containers

  • Python has many built-in container types: lists, tuples, dictionaries, etc. but it also has a protocol for defining custom container classes

  • Defining custom containers is as easy as implementing the magic methods
    • __len__, which is called by len
    • __getitem__, which is used in collection[indexing]
    • __contains__, which is checks if an item in collection

  • To create a mutable container, we can also implement the __setitem__ and __delitem__ methods

Summary

  • Inheritance allows us to implement relationships between classes and simplify our programs

  • Interfaces allow for standardized interaction between different components by defining rules for communication
    • Implementing interfaces in Python can allow our custom classes to behave like built-in classes

  • Both are tools for abstraction, and learning them well is one of the keys to becoming a great object-oriented programmer
16 - Inheritance & Interfaces - Google Slides