Source

python_koans / python3 / koans / about_multiple_inheritance.py

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

#
# Slightly based on AboutModules in the Ruby Koans
#

from runner.koan import *

class AboutMultipleInheritance(Koan):
    class Nameable:
        def __init__(self):
            self._name = None

        def set_name(self, new_name):
            self._name = new_name
    
        def here(self):
            return "In Nameable class"
       
    class Animal:            
        def legs(self):
            return 4

        def can_climb_walls(self):
            return False
        
        def here(self):
            return "In Animal class"
                                            
    class Pig(Animal):
        def __init__(self):
            super().__init__()
            self._name = "Jasper"

        @property
        def name(self):
            return self._name
           
        def speak(self):
            return "OINK"
        
        def color(self):
            return 'pink'        
    
        def here(self):
            return "In Pig class"

    class Spider(Animal):
        def __init__(self):
            super().__init__()
            self._name = "Boris"

        def can_climb_walls(self):
            return True

        def legs(self):
            return 8

        def color(self):
            return 'black'

        def here(self):
            return "In Spider class"

    class Spiderpig(Pig, Spider, Nameable):
        def __init__(self):
            super(AboutMultipleInheritance.Pig, self).__init__()
            super(AboutMultipleInheritance.Nameable, self).__init__()
            self._name = "Jeff"
    
        def speak(self):
            return "This looks like a job for Spiderpig!"
    
        def here(self):
            return "In Spiderpig class"
        
    # 
    # Hierarchy:   
    #               Animal
    #              /     \  
    #            Pig   Spider  Nameable 
    #              \      |      /
    #                 Spiderpig
    #    
    # ------------------------------------------------------------------
  
    def test_normal_methods_are_available_in_the_object(self):
        jeff = self.Spiderpig()
        self.assertRegexpMatches(jeff.speak(), __)

    def test_base_class_methods_are_also_available_in_the_object(self):
        jeff = self.Spiderpig()
        try:
            jeff.set_name("Rover")
        except:
            self.fail("This should not happen")
        self.assertEqual(__, jeff.can_climb_walls())
  
    def test_base_class_methods_can_affect_instance_variables_in_the_object(self):
        jeff = self.Spiderpig()
        self.assertEqual(__, jeff.name)
        
        jeff.set_name("Rover")
        self.assertEqual(__, jeff.name)
  
    def test_left_hand_side_inheritance_tends_to_be_higher_priority(self):
        jeff = self.Spiderpig()
        self.assertEqual(__, jeff.color())

    def test_super_class_methods_are_higher_priority_than_super_super_classes(self):
        jeff = self.Spiderpig()
        self.assertEqual(__, jeff.legs())

    def test_we_can_inspect_the_method_resolution_order(self):
        #
        # MRO = Method Resolution Order
        #
        mro = type(self.Spiderpig()).mro()
        self.assertEqual('Spiderpig', mro[0].__name__)
        self.assertEqual('Pig', mro[1].__name__)
        self.assertEqual(__, mro[2].__name__) 
        self.assertEqual(__, mro[3].__name__) 
        self.assertEqual(__, mro[4].__name__) 
        self.assertEqual(__, mro[5].__name__) 

    def test_confirm_the_mro_controls_the_calling_order(self):
        jeff = self.Spiderpig()
        self.assertRegexpMatches(jeff.here(), 'Spiderpig')
        
        next = super(AboutMultipleInheritance.Spiderpig, jeff)      
        self.assertRegexpMatches(next.here(), 'Pig')

        next = super(AboutMultipleInheritance.Pig, jeff)
        self.assertRegexpMatches(next.here(), __)
        
        # Hang on a minute?!? That last class name might be a super class of
        # the 'jeff' object, but its hardly a superclass of Pig, is it?
        #
        # To avoid confusion it may help to think of super() as next_mro().