473,288 Members | 1,718 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,288 software developers and data experts.

object inheritance

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.extend_from(a)
b.foo()
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.extend_from(a)
b.foo()
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?

Oct 26 '07 #1
8 1474
Can you tell any specific use case for doing this?

Regards,
Pradeep

On 10/26/07, Anand <an********@gmail.comwrote:
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.extend_from(a)
b.foo()
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.extend_from(a)
b.foo()
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?

--
http://mail.python.org/mailman/listinfo/python-list
Oct 26 '07 #2
On Oct 26, 5:31 pm, "Pradeep Jindal" <praddyjin...@gmail.comwrote:
Can you tell any specific use case for doing this?
I have many implementaions of a db interface.

SimpleDB - simple implementation
BetterDB - optimized implementation
CachedDB - an implementation with caching of queries
RestrictedDB - implementation with permissions

Now, I want to combine these implementations and use.
Typical use case scenarios are:

db = RestrictedDB(CachedDB(SimpleDB()))
db = RestrictedDB(SimpleDB())
db = RestrictedDB(BetterDB())
db = RestrictedDB(CachedDB(BetterDB())
db = CachedDB(SimpleDB())
etc..

Oct 26 '07 #3
On Friday 26 Oct 2007 6:21:57 pm Anand wrote:
On Oct 26, 5:31 pm, "Pradeep Jindal" <praddyjin...@gmail.comwrote:
Can you tell any specific use case for doing this?

I have many implementaions of a db interface.

SimpleDB - simple implementation
BetterDB - optimized implementation
CachedDB - an implementation with caching of queries
RestrictedDB - implementation with permissions

Now, I want to combine these implementations and use.
Typical use case scenarios are:

db = RestrictedDB(CachedDB(SimpleDB()))
db = RestrictedDB(SimpleDB())
db = RestrictedDB(BetterDB())
db = RestrictedDB(CachedDB(BetterDB())
db = CachedDB(SimpleDB())
etc..
I agree with Duncan. According to me, this should be called Delegation rather
than inheritance. And delegation should work without any conflicts of
identifier names and all that. I think, it should be all about several
objects implementing a protocol (interface) and that should work cleanly.
Oct 27 '07 #4
On Oct 28, 1:16 am, Pradeep Jindal <praddyjin...@gmail.comwrote:
On Friday 26 Oct 2007 6:21:57 pm Anand wrote:
On Oct 26, 5:31 pm, "Pradeep Jindal" <praddyjin...@gmail.comwrote:
Can you tell any specific use case for doing this?
I have many implementaions of a db interface.
SimpleDB - simple implementation
BetterDB - optimized implementation
CachedDB - an implementation with caching of queries
RestrictedDB - implementation with permissions
Now, I want to combine these implementations and use.
Typical use case scenarios are:
db = RestrictedDB(CachedDB(SimpleDB()))
db = RestrictedDB(SimpleDB())
db = RestrictedDB(BetterDB())
db = RestrictedDB(CachedDB(BetterDB())
db = CachedDB(SimpleDB())
etc..

I agree with Duncan. According to me, this should be called Delegation rather
than inheritance. And delegation should work without any conflicts of
identifier names and all that. I think, it should be all about several
objects implementing a protocol (interface) and that should work cleanly.
I don't think so. It is not as simple as delegation.

In the example that I gave previously, call to self.say in A.foo
calls B.say not A.say, which I think is not possible with delegation.


Oct 31 '07 #5
En Wed, 31 Oct 2007 00:36:34 -0300, Anand <an********@gmail.comescribió:
>No, that is an argument for multiple-inheritance, mixin classes etc. You
know when constructing the object what behaviour you want it to have. It
isn't an argument for changing the behaviour of an existing object
dynamically.
Partially true. I don't want to change the behavior of an exiting
object. I know what behavior I want to have at the time of creating.
This can be achieved by creating classes dynamically by parameterizing
the base class, which I thought is ugly.
If you know at compile time which features you want, you can use multiple
inheritance to define the new class.
If you only know the set of clases to mix at run time, you can dinamically
create new classes with 'type':

newclass = type('newclass', (CachedDB, SimpleDB), {})
db = newclass()
db.withIDs will call CachedDB.withID, as you want.

[In another message]
In the example that I gave previously, call to self.say in A.foo
calls B.say not A.say, which I think is not possible with delegation.
It's easy to create a new type inheriting from your classes:

obj = type('', (B,A), {})()
obj.foo()
should print: b.say "foo"

--
Gabriel Genellina

Oct 31 '07 #6
On Oct 31, 8:26 am, Anand <anandol...@gmail.comwrote:
On Oct 28, 1:16 am, Pradeep Jindal <praddyjin...@gmail.comwrote:
On Friday 26 Oct 2007 6:21:57 pm Anand wrote:
On Oct 26, 5:31 pm, "Pradeep Jindal" <praddyjin...@gmail.comwrote:
Can you tell any specific use case for doing this?
I have many implementaions of a db interface.
SimpleDB - simple implementation
BetterDB - optimized implementation
CachedDB - an implementation with caching of queries
RestrictedDB - implementation with permissions
Now, I want to combine these implementations and use.
Typical use case scenarios are:
db = RestrictedDB(CachedDB(SimpleDB()))
db = RestrictedDB(SimpleDB())
db = RestrictedDB(BetterDB())
db = RestrictedDB(CachedDB(BetterDB())
db = CachedDB(SimpleDB())
etc..
I agree with Duncan. According to me, this should be called Delegation rather
than inheritance. And delegation should work without any conflicts of
identifier names and all that. I think, it should be all about several
objects implementing a protocol (interface) and that should work cleanly.

I don't think so. It is not as simple as delegation.

In the example that I gave previously, call to self.say in A.foo
calls B.say not A.say, which I think is not possible with delegation.
Let me explain what I meant, its all about several objects (e.g. "a")
implementing a protocol, in your case the "say" method, and some
object (e.g. "b") extending those objects by adding some more
functionality but requiring that those objects, that it extends from,
follow a specific protocol ("a" must have say method). Also note that,
"B" or "b" is partial implementation of what its meant for, I mean,
calling "b"'s "say" will not work if "b" has not yet extended from "a"
or any other object implementing the same protocol.

Less time, can't get into more details. Bye for now.

Thanks
-Pradeep

Oct 31 '07 #7
On Oct 31, 9:57 am, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:
En Wed, 31 Oct 2007 00:36:34 -0300, Anand <anandol...@gmail.comescribió:
No, that is an argument for multiple-inheritance, mixin classes etc. You
know when constructing the object what behaviour you want it to have. It
isn't an argument for changing the behaviour of an existing object
dynamically.
Partially true. I don't want to change the behavior of an exiting
object. I know what behavior I want to have at the time of creating.
This can be achieved by creating classes dynamically by parameterizing
the base class, which I thought is ugly.

If you know at compile time which features you want, you can use multiple
inheritance to define the new class.
If you only know the set of clases to mix at run time, you can dinamically
create new classes with 'type':

newclass = type('newclass', (CachedDB, SimpleDB), {})
db = newclass()
db.withIDs will call CachedDB.withID, as you want.
Interesting.

CachedDB.withID should call withID from its super class (here
SimpleDB), when it is not in cache. How to do that?
Oct 31 '07 #8
En Wed, 31 Oct 2007 19:26:17 -0300, Anand <an********@gmail.comescribió:
On Oct 31, 9:57 am, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:
>>
If you know at compile time which features you want, you can use
multiple
inheritance to define the new class.
If you only know the set of clases to mix at run time, you can
dinamically
create new classes with 'type':

Interesting.

CachedDB.withID should call withID from its super class (here
SimpleDB), when it is not in cache. How to do that?
Using super(). See
<http://docs.python.org/dev/tutorial/classes.html#multiple-inheritance>
and <http://www.python.org/2.3/mro.htmlfor the details.

This is a running version of your example:

pyclass SimpleDB(object):
.... def withID(self, id):
.... print "SimpleDB.withID",id
.... return "Data for %s" % id
.... def withIDs(self, ids):
.... return [self.withID(id) for id in ids]
....
pyclass CachedDB(object):
.... def __init__(self):
.... # CachedDB instances must have a cache dictionary
.... super(CachedDB, self).__init__(self)
.... self.cache = {}
.... def withID(self, id):
.... print "CachedDB.withID",id
.... res = self.cache.get(id)
.... if res is None:
.... print "cache miss!"
.... self.cache[id] = res = super(CachedDB, self).wit
hID(id)
.... return res
....
pynewclass = type('newclass', (CachedDB, SimpleDB), {})
pydb = newclass()
pyprint db.withIDs([1,2,1,3,2,1])
CachedDB.withID 1
cache miss!
SimpleDB.withID 1
CachedDB.withID 2
cache miss!
SimpleDB.withID 2
CachedDB.withID 1
CachedDB.withID 3
cache miss!
SimpleDB.withID 3
CachedDB.withID 2
CachedDB.withID 1
['Data for 1', 'Data for 2', 'Data for 1', 'Data for 3', 'Data f
or 2', 'Data for 1']

Multiple inheritance is not the only option. You may want to read about
decorators too: instead of overriding the method withID, you can decorate
it with some variant of the "memoize" decorator. Look for the (excellent!)
article on decorators by Michele Simionato.

--
Gabriel Genellina

Nov 1 '07 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Az Tech | last post by:
Hi people, (Sorry for the somewhat long post). I request some of the people on this group who have good experience using object-orientation in the field, to please give some good ideas for...
6
by: Squeamz | last post by:
Hello, Say I create a class ("Child") that inherits from another class ("Parent"). Parent's destructor is not virtual. Is there a way I can prevent Parent's destructor from being called when a...
14
by: Craig Buchanan | last post by:
If I have two custom vb.net classes, where 80% of the properties are alike and there is one method with a matching signature, can i cast between one and the other? do i need to have each class...
8
by: Raterus | last post by:
Hi, I don't even know if this can be done.. Lets say I have two objects, --- Public Class Employee End Class
3
by: Robert Abi Saab | last post by:
Hi everyone. I just finished a course on PostgreSQL and I found out that PostgreSQL doesn't provide any object relational features (as claimed in the official documentation), except table...
73
by: Water Cooler v2 | last post by:
I am new to PHP, just one day new. But I am otherwise a seasoned programmer on many other languages like C, VB 6, C#, VB.NET, Win32 platform and have some tiny bit experience in MFC, C++, Python. ...
23
by: digitalorganics | last post by:
How can an object replace itself using its own method? See the following code: class Mixin: def mixin(object, *classes): NewClass = type('Mixin', (object.__class__,) + classes, {}) newobj =...
6
by: burningodzilla | last post by:
Hi all - I'm preparing to dive in to more complex application development using javascript, and among other things, I'm having a hard time wrapping my head around an issues regarding "inheritance"...
3
by: jacobstr | last post by:
I've noticed Object.extend used in a few different ways and I'm having trouble distinguishing why certain usages apply to a given situation. On line 804 Ajax.Base is defined as follows: ...
3
by: Rahul | last post by:
While reading Inside the C++ object model I came through the following paragraph Point3d origin, *ptr = &origin; A) origin.x = 0.0; B) ptr->x = 0.0; The book says "A & B statements performs...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: marcoviolo | last post by:
Dear all, I would like to implement on my worksheet an vlookup dynamic , that consider a change of pivot excel via win32com, from an external excel (without open it) and save the new file into a...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.