Saturday, December 27, 2014

A bit of fun with Jabberwocky, classes, mixins, python and method resolution order (MRO)

I was trying to figure out and demonstrate python's Member Resolution Order... In particular, pay attention to the output from __str__...

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class BeastBase(dict):
  def __init__(self, **characteristics):
    super(BeastBase, self).__init__(**characteristics)

  def __str__(self):
    return "; ".join(["%s=%r"%item for item in super(BeastBase, self).iteritems()])

class Mixin(object): pass

class BitingMixin(Mixin):
  def __init__(self, jaws=2, teeth_per_mouth=32, **characteristics):
    self.jaws=jaws
    self.teeth_per_mouth=teeth_per_mouth
    super(BitingMixin, self).__init__(**characteristics)

  def bite(self):
    print "Bite: jaws=%s, teeth=%s"%(self.jaws, self.teeth_per_mouth*self.jaws/2)

  def __str__(self):
    return "Jawed: %s; %s"%(self.jaws, super(BitingMixin, self).__str__())

class JawedBeast(BeastBase, BitingMixin): pass

class ClawingMixin(Mixin):
  def __init__(self, feet=4, toes_per_foot=3, **characteristics):
    self.feet=feet
    self.toes_per_foot=toes_per_foot
    super(ClawingMixin, self).__init__(**characteristics)

  def catch(self):
    print "Catch: feet=%s, toes=%s"%(self.feet, self.toes_per_foot*self.feet)

  def __str__(self):
    return "Claws: %s; %s"%(self.toes_per_foot*self.feet, super(ClawingMixin, self).__str__())

class ClawedBeast(BeastBase, ClawingMixin): pass

class FlamingMixin(Mixin):
  def __init__(self, eyes=6, flames_per_eye=1, **characteristics):
    self.eyes=eyes
    self.flames_per_eye=flames_per_eye
    super(FlamingMixin, self).__init__(**characteristics)

  def flame(self):
    print "Flames:", self.eyes*self.flames_per_eye

  def __str__(self):
    return "Eyes: %s, Flames: %s; %s"%(self.eyes, self.eyes*self.flames_per_eye, super(FlamingMixin, self).__str__())

class FlamedBeast(FlamingMixin, BeastBase): pass

class WhifflingMixin(Mixin):
  def whiffle(self): print "Whiffle...."
  def __str__(self): return "Whiffling... "+super(WhifflingMixin, self).__str__()

class WhifflingBeast(WhifflingMixin, BeastBase): pass

class BurblingMixin(Mixin):
  def burble(self): print "Burble...."
  def __str__(self): return "Burbling... "+super(BurblingMixin, self).__str__()

class BurblingBeast(BurblingMixin, BeastBase): pass

class Jabberwocky(BitingMixin, ClawingMixin, FlamingMixin, WhifflingMixin, BurblingMixin, BeastBase):
  def __init__(self, **characteristics):
    super(Jabberwocky, self).__init__(**characteristics)

  def __str__(self):
    return "JabberWocky: "+super(Jabberwocky, self).__str__()+" ... Beware! "

if __name__ == "__main__":

# Beware the Jabberwock, my son!
  jabberwocky1=Jabberwocky(personality="Friendly", consideration="Temperamental", eyes=5, flames_per_eye=3)
  print jabberwocky1

# Beware the Jubjub bird, and shun
# The frumious Bandersnatch!

# The jaws that bite, the claws that catch!
  jabberwocky1.bite()
  jabberwocky1.catch()

# And as in uffish thought he stood,
# The Jabberwock, with eyes of flame,
  jabberwocky1.flame()

# Came whiffling through the tulgey wood,
  jabberwocky1.whiffle()
# And burbled as it came!
  jabberwocky1.burble()  

Output:
JabberWocky: Jawed: 2; Claws: 12; Eyes: 5, Flames: 15; Whiffling... Burbling... consideration='Temperamental'; personality='Friendly' ... Beware!
Bite: jaws=2, teeth=32
Catch: feet=4, toes=12
Flames: 15
Whiffle....
Burble....