Is-A Duck

3 Ways to Reuse Code

Has-A Duck

Calls-A Duck

Janet Riley                 @janet_riley_net

Online Intro

These slides are from a lightning talk I gave to Boston PyLadies.  The examples are geared to Python, but the content  applies to languages that  have classes and modules.


Press the space bar to advance sequentially.


Use the blue arrows in the corner to dive into a section or skip around. 


Speaker notes are overlaid in grey.

3 Common Approaches

  • inheritance
  • composition
  • modules and libraries


the eternal


Is-A Duck



class Duck:

    def looks_like(self):
        print("You see here a duck.")

    def swim(self):
        print("Paddle, paddle, paddle")

    def quack(self):



Just like the parent class, except a little different

Reason #1: 


add * extend * override

>>> plain_dict = dict()
>>> print( plain_dict['no_such_key']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'no_such_key'
KeyError: 'no_such_key'


defaultdict inherits from dict.

It's just like its parent, with one difference:

>>> import collections
>>> my_default_dict = collections.defaultdict(int)
>>> print( my_default_dict['no_such_key'])

Python dict() is a key-value map.

It raises an error if we access a key that doesn't exist.

Reason #2:


Dr. Liskov

look like a duck

swim like a duck

quack like a duck


A substitute duck must:



The 'L' in the SOLID principle

have duck DNA


And in some languages,

Has-A Duck


import RubberDucky

class Ernie:

    def __init__(self):
        self.ducky = RubberDucky()

    def sing(self):
        print("Rubber ducky, you're the one")
        print( self.ducky.quack())
        print( self.ducky.quack())
        print("You make bath time lots of fun")

Ernie has a duck.

Ernie is not a duck.


  • weaker relationship between elements
  • more configurable
  • less baggage
  • my implementation is nobody else's business

Calls-A Duck

good old modules

group related code into namespaces

which keeps them tidy


often without classes

import json

duck = json.loads('{"name":"Daffy Duck", \
                    "species":"Loony Tune"}')

How to Choose

when to ask questions


  • when possible
  • when nothing calls the object from the outside
  • when configurability is a plus


  • when necessary
  • when it's just like the parent with a small difference 


  • all static methods or constants
  • no instance data
  • useful across many kinds of things
  • "when your class has 2 methods, one of which is __init__"


  • there are distinct instances with data
  • inheritance is required

No Trogdors!

class Trogdor(Dragon, Man):

    def burninate(self):

    def shake_hands(self):

"Trogdor was a Man!

He was a Dragon Man!

Maybe he was just a dragon..."


Too Many Ancestors


inherits bill, eggs from Duck

inherits fur, tail from Beaver

inherits poison spurs from Ninja

Lots of Imports

Learn More

The Art of Subclassing - Raymond Hettinger


Stop Writing Classes - Jack Diederich


Practical Object-Oriented Design in Ruby - Sandi Metz

An articulate and approachable guide to object design. If you know Python, you'll understand the Ruby well enough. 


Trogdor the Burninator -

See the social and domain forces that lead to strange inheritance trees.

Image Credits