class Prototype(object):
def __init__(self, *args):
self._parents = []
for each in args:
self._parents.append(each)
def clone(self, *args):
return self.__class__(self, *args)
def __getattr__(self, name):
for each in self._parents:
try:
return getattr(each, name)
except AttributeError:
pass
raise AttributeError(name)
The implementation is suprisingly simple: three methods!
The first is the initialize method for new instances. It takes a list of objects that we will use as the parents of our new object. Of course, by simply calling Prototype's constructor with no arguments, we get a clean object. I made the ability to have multiple inheritance simple because of Self.
The second method is the clone method and it simply calls the constructor for another object makes itself the first parent with the rest of the arguments becoming the other parents. Nothing to it!
The last method is the real meat. It only get called by the Python engine when an attribute fails to be looked up. All I do is call each parent and if one succeeds, it returns the answer. This is a depth first search of the parent hierarchy. Simple.
And that's all we need to implement prototypes in Python. Now, I just need to explain some practical uses of this in some later blog entries.
How do I know all of this works? Here's my tests:
import unittest
class Test(unittest.TestCase):
def testSimple(self):
parent = Prototype()
child = parent.clone()
parent.value = 0
self.assertEquals(0, child.value)
child.value = 1
self.assertEquals(1, child.value)
self.assertEquals(0, parent.value)
self.failUnlessRaises(AttributeError, lambda:parent.unknown)
def testMultipleParents(self):
parent1 = Prototype()
parent2 = Prototype()
child = parent1.clone(parent2)
parent2.value = 2
self.failUnlessRaises(AttributeError, lambda:parent1.value)
self.assertEquals(2, child.value)
If anyone sees anything wrong in my implementation or un-Pythonic let me know. I'm still learning, but I thought it would be cool to show my progress.