updated 2010-06-15T09:45:00Z
:
- added an example for the "classes as instances" approach, and an explanation of the "instances as classes" approach; incorporated and referenced Alex Martelli's answer;
I'm wondering how to implement prototypal inheritance in Python. There would seem to be two different approaches to this problem: classes as instances, and instances as classes.
The second method would seem to be more flexible, in that it could be applied to existing objects of varied types, while the first would likely be more convenient for typical use cases.
classes as instances
The idea here is to use a metaclass to cause instantiations to actually be classes, rather than objects. This approach looks something like this:
class ClassAsInstance(type):
""" ClassAsInstance(type)\n
>>> c = ClassAsInstance()
>>> c.prop = 6
It's sort of annoying to have to make everything a class method.
>>> c.jef = classmethod(lambda self: self.prop)
>>> c.jef()
6
>>> cc = c()
>>> cc.jef()
6
But it works.
>>> c.prop = 10
>>> cc.jef()
10
>>> c.jef = classmethod(lambda self: self.prop * 2)
>>> cc.jef()
20
"""
def __new__(self):
return type(self.__name__ + " descendant", (self, ), {})
I haven't really tested any complicated stuff with this approach, so it may have limitations.
instances as classes
With this approach, the idea is to use the type
constructor to create classes from objects. This is exemplified in Alex Martelli's answer, although the example he uses for this approach implements copy prototyping rather than allowing the descendants to inherit later changes to their prototypes.
My approach was to do something like this:
def createDescendant(obj):
return type(obj.__class__.__name__ + " descendant", (obj.__class__, ), obj.__dict__)()
which will work in sort of a javascript-y kind of way: changes to a given object will not influence its descendants, but changes to the parent object's __class__
(like a javascript prototype
) will. I gather that this is because the type
constructor copies obj.__dict__
rather than referencing it in some sort of mro-ish scheme.
I attempted to implement an improved version that would allow true prototypal inheritance, wherein objects would inherit updates to the parent objects. The idea was to assign the prototype object's __dict__
property to the same property of the newly-created class, the one that becomes the class of the descendant object.
However, this didn't work out, as I discovered that the __dict__
of a type
cannot be assigned to; this limitation also applies to classes derived from type
. I'm still curious if it's possible to get around this problem by creating an object that "implements the type protocol", as is done with iterables, sequences, etc., but does not actually inherit from type
. This might create other problems, such as those inherent to the delegational approach that Alex mentions in the first part of his answer.
delegation
Alex also suggests a third approach, that of delegation, wherein the state of an object is propagated to descendant objects via the __getattr__
magic method. Again, see Alex's answer for an example, as well as details on the limitations of this approach.
Further insights on the practicality of these approaches, as well as alternative suggestions, are hereby requested.