A
Anand
I am trying to implement some kind of object inheritance. Just like
one class can extend from another, I want to do the same on objects
dynamically.
I just thought that I can share my excitement here.
Suppose there are classes A and B and their instances a and b.
class A:
def foo(self): self.say('foo')
def say(self, msg):
print 'a.say', msg
class B:
def say(self, msg):
print 'b.say', msg
a = A()
b = B()
I want b to inherit the behavior of a.
b.say foo
I looked around and found that some people talked about similar ideas,
but didn't find any concrete implementation.
I came up with the following implementation using meta-classes.
class ExtendMetaClass(type):
def __init__(cls, *a, **kw):
# take all attributes except special ones
keys = [k for k in cls.__dict__.keys() if not
k.startswith('__')]
d = [(k, getattr(cls, k)) for k in keys]
# remove those attibutes from class
for k in keys:
delattr(cls, k)
# remember then as dict _d
cls._d = dict(d)
def curry(f, arg1):
def g(*a, **kw):
return f(arg1, *a, **kw)
g.__name__ = f.__name__
return g
def _getattr(self, name):
"""Get value of attribute from self or super."""
if name in self.__dict__:
return self.__dict__[name]
elif name in self._d:
value = self._d[name]
if isinstance(value, types.MethodType):
return curry(value, self)
else:
return value
else:
if self._super != None:
return self._super._getattr(name)
else:
raise AttributeError, name
def __getattr__(self, name):
"""Returns value of the attribute from the sub object.
If there is no sub object, self._getattr is called.
"""
if name.startswith('super_'):
return self._super._getattr(name[len('super_'):])
if self._sub is not None:
return getattr(self._sub, name)
else:
return self._getattr(name)
def extend_from(self, super):
"""Makes self extend from super.
"""
self._super = super
super._sub = self
cls.__getattr__ = __getattr__
cls._getattr = _getattr
cls._super = None
cls._sub = None
cls.extend_from = extend_from
class Extend:
__metaclass__ = ExtendMetaClass
def __init__(self, super=None):
if super:
self.extend_from(super)
And the above example becomes:
class A(Extend):
def foo(self): self.say('foo')
def say(self, msg):
print 'a.say', msg
class B(Extend):
def say(self, msg):
print 'b.say', msg
# self.super_foo calls foo method on the super object
self.super_say('super ' + msg)
a = A()
b = B()
b.say foo
a.say super foo
There are one issue with this approach. Once b extends from a,
behavior of a also changes, which probably should not. But that
doesn't hurt me much.
Any comments?
one class can extend from another, I want to do the same on objects
dynamically.
I just thought that I can share my excitement here.
Suppose there are classes A and B and their instances a and b.
class A:
def foo(self): self.say('foo')
def say(self, msg):
print 'a.say', msg
class B:
def say(self, msg):
print 'b.say', msg
a = A()
b = B()
I want b to inherit the behavior of a.
b.say foo
I looked around and found that some people talked about similar ideas,
but didn't find any concrete implementation.
I came up with the following implementation using meta-classes.
class ExtendMetaClass(type):
def __init__(cls, *a, **kw):
# take all attributes except special ones
keys = [k for k in cls.__dict__.keys() if not
k.startswith('__')]
d = [(k, getattr(cls, k)) for k in keys]
# remove those attibutes from class
for k in keys:
delattr(cls, k)
# remember then as dict _d
cls._d = dict(d)
def curry(f, arg1):
def g(*a, **kw):
return f(arg1, *a, **kw)
g.__name__ = f.__name__
return g
def _getattr(self, name):
"""Get value of attribute from self or super."""
if name in self.__dict__:
return self.__dict__[name]
elif name in self._d:
value = self._d[name]
if isinstance(value, types.MethodType):
return curry(value, self)
else:
return value
else:
if self._super != None:
return self._super._getattr(name)
else:
raise AttributeError, name
def __getattr__(self, name):
"""Returns value of the attribute from the sub object.
If there is no sub object, self._getattr is called.
"""
if name.startswith('super_'):
return self._super._getattr(name[len('super_'):])
if self._sub is not None:
return getattr(self._sub, name)
else:
return self._getattr(name)
def extend_from(self, super):
"""Makes self extend from super.
"""
self._super = super
super._sub = self
cls.__getattr__ = __getattr__
cls._getattr = _getattr
cls._super = None
cls._sub = None
cls.extend_from = extend_from
class Extend:
__metaclass__ = ExtendMetaClass
def __init__(self, super=None):
if super:
self.extend_from(super)
And the above example becomes:
class A(Extend):
def foo(self): self.say('foo')
def say(self, msg):
print 'a.say', msg
class B(Extend):
def say(self, msg):
print 'b.say', msg
# self.super_foo calls foo method on the super object
self.super_say('super ' + msg)
a = A()
b = B()
b.say foo
a.say super foo
There are one issue with this approach. Once b extends from a,
behavior of a also changes, which probably should not. But that
doesn't hurt me much.
Any comments?