on Sep 11th, 2008Prototype based programming in python
Revision #2:
I updated my code with some more bells and whistles, also removing the double-underscore-method/attributes and operator overloading as some people commented so “nicely” on.
prototype.py
class Object(object):
def __init__(self):
self._parent = None
self._methods = {}
def clone(self):
o = Object()
o._parent = self
return o
def _getmethod(self, name):
try:
return self._methods[name]
except KeyError:
return self._parent._getmethod(name)
def __getattr__(self, name):
method = self._getmethod(name)
if isinstance(method, Method) and method.object is not self:
self._methods[name] = self._methods[name] = Method(method.method, self)
return self._methods[name]
class Method(object):
def __init__(self, method, object = None):
self.method = method
self.object = object
def __call__(self, *args, **kw):
return self.method(self.object, *args, **kw)
def method(obj):
def decorator(f):
obj._methods[f.__name__] = Method(f, obj)
return obj._methods[f.__name__]
return decorator
def siblings(a, b):
return a._parent is b._parent
def mixin(into, mixin):
if isinstance(mixin, Object):
for name, wrapper in mixin._methods.iteritems():
into._methods[name] = wrapper
def child_of(child, parent):
comp = child
while comp is not None:
if comp is parent:
return True
comp = comp._parent
return False
def sibling(obj):
return obj._parent.clone()
def is_prototype(obj):
return typeof(obj) is Object
def clone():
return Object()
and, demo.py
import prototype as p
from prototype import method
# Basic usage example
animal = p.clone()
animal.name = None
cat = animal.clone()
cat.name = "Cat"
cat.color = None
@method(cat)
def meow(self, times = 1):
print ("%s says meow, and is of the color %s" % (self.name, self.color))*times
nermal = cat.clone()
nermal.name = "Nermal"
nermal.color = "grey"
garfield = p.sibling(nermal) # same as cat.clone() or nermal._parent.clone()
garfield.name = "Garfield"
garfield.color = "orange"
print cat.name
print garfield.name
print nermal.name
cat.meow()
garfield.meow()
nermal.meow()
kitten_1 = garfield.clone()
kitten_1.name = "Kiten #1"
kitten_1.color = "brown"
kitten_2 = p.sibling(kitten_1)
kitten_2.name = "Kitten #2"
kitten_2.color = "White"
garfield.name = "Garfield ..."
garfield.color = "Orange ..."
cat.name = "Original cat"
cat.color = "Still none"
cat.meow()
garfield.meow()
nermal.meow()
kitten_1.meow()
kitten_2.meow()
# Mixin example
mixin = p.clone()
@method(mixin)
def say_name_two_times(self):
print self.name*2
@method(mixin)
def say_name_three_times(self):
print self.name*5
p.mixin(garfield, mixin)
garfield.say_name_two_times()
garfield.say_name_three_times()
print p.child_of(garfield, cat)
print p.child_of(nermal, garfield)
print p.siblings(nermal, garfield)
, will print something like this:
Cat Garfield Nermal Cat says meow, and is of the color None Garfield says meow, and is of the color orange Nermal says meow, and is of the color grey Original cat says meow, and is of the color Still none Garfield ... says meow, and is of the color Orange ... Nermal says meow, and is of the color grey Kiten #1 says meow, and is of the color brown Kitten #2 says meow, and is of the color White Garfield ...Garfield ... Garfield ...Garfield ...Garfield ...Garfield ...Garfield ... True False True
I love python.
Original version of the code
Revision #1:
class Object(object):
def __init__(self):
self.__parent__ = None
self.__methods__ = {}
def clone(self):
o = Object()
o.__parent__ = self
return o
def __pos__(self):
return self.clone()
def __getmethod__(self, name):
try:
return self.__methods__[name]
except KeyError:
return self.__parent__.__getmethod__(name)
def __getattr__(self, name):
method = self.__getmethod__(name)
if isinstance(method, Method) and method.object is not self:
method = self.__methods__[name] = Method(method.method, self)
return method
class Method(object):
def __init__(self, method, object = None):
self.method = method
self.object = object
def __call__(self, *args, **kw):
return self.method(self.object, *args, **kw)
def __isbound__(self):
return object != None
def method(obj):
def decorator(f):
_method = Method(f, obj)
obj.__methods__[f.__name__] = _method
return _method
return decorator
if __name__ == "__main__":
animal = Object()
cat = +animal
cat.name = None
@method(cat)
def meow(self, times=1):
print ("%s says meow " % self.name)*times
cat.meow()
fluffy = +cat
fluffy.name = "fluffy"
fluffy.meow()
cat.name = "original cat"
cat.meow()
fluffy.meow()
puffy = +fluffy
puffy.name = "puffy"
puffy.meow()
fluffy.meow()
cat.meow()
The above prints:
None says meow fluffy says meow original cat says meow fluffy says meow puffy says meow fluffy says meow original cat says meow
A very simple example on how to work with prototype-based programming in Python.
