Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Potential improvement on delegation via explicit calls and super

Reply
Thread Tools

Potential improvement on delegation via explicit calls and super

 
 
Robert Dick
Guest
Posts: n/a
 
      12-17-2004
Derived classes sometimes need to delegate portions of the work in overridden
methods to methods in their base classes. This was traditionally done with
explicit calls in python, e.g.,

class Derived(Left, Right):
def __init__(self, myarg, larg, rarg):
Left.__init__(self, larg)
Right.__init__(self, rarg)
self.data = myarg
print 'derived'

This worked great. It was possible to grab the appropriate arguments and send
them off to the right point. However, there was a problem.

class Base:
def __init__(self):
print 'base'

class Left(Base):
def __init__(self, arg):
Base.__init__(self)
print 'left'

class Right(Base):
def __init__(self, arg):
Base.__init__(self)
print 'right'

Now, when Derived(Left, Right) is initialized, Base.__init__ is called twice.
Sometimes that's O.K. Usually, it's a bad thing. Along came new-style
classes and 'super'. Unfortunately, super-based delegation doesn't play
nicely with traditional classes.
http://www.ai.mit.edu/people/jknight/super-harmful/
Moreover, it undermines any attempts to control which subset of arguments go
to which base class. This second problem is serious. In real life, base
classes differ from each other: I need to be able to send the right arguments
to each.

What I really want to do is explicitly delegate tasks to base classes,
choosing the arguments to send to each, but avoid double-calls resulting from
reconverging paths in the inheritance directed acyclic (pray it's acyclic)
graph.

I think the appended code may solve this problem, play nicely with traditional
classes, and allow the coder to send the right arguments to the right base
classes.

However, I'm new to python so I need some help.

1) Is my thinking reasonable or is there an better way to solve the
reconvergent path problem in python without undermining control over
arguments?

2) What's the proper way to rewrite the appended code. I'm sure it's
dreadfully inefficient. There are also probably ways to make its use more
intuitive, but I'm new to the language so I don't know the tricks yet.

Thanks for any tips,

-Robert Dick-

----
'''See the example at the bottom.'''

import inspect

def flatten_tree(tree):
'''Flatten a tree represented by nested lists'''
if isinstance(tree, list):
return [j for i in tree for j in flatten_tree(i)]
else:
return (tree,)

# Cache for delegation decisions.
call_cache = set()

def should_call(self, pos, supr):
'''Examines the inheritance DAG (might work for DCGs, too... haven't
checked) for 'self' to determine whether 'pos' is the leftmost derived
for 'supr'. Returns bool. Caches results for performance.'''
if (self.__class__, pos, supr) in call_cache: return True
ct = flatten_tree(inspect.getclasstree(inspect.getmro(s elf.__class__),
True))
# ct is a list of (class, (base classes)) tuples
# Find the first instance of the supr as a base class
do_call = pos is [cls for cls, bases in ct if supr in bases][0]
if do_call: call_cache.add((self.__class__, pos, supr))
return do_call

def delegate(self, pos, s_call, *pargs, **kargs):
'''If 'pos' is the leftmost derived for 's_call' in the 'self' inheritance
DAG, call s_call with 'pargs' and 'kargs'.'''
if inspect.ismethoddescriptor(s_call):
supr = s_call.__objclass__
else:
supr = s_call.im_class
if should_call(self, pos, supr):
s_call(self, *pargs, **kargs)

if __name__ == '__main__':
class Base(object):
def __init__(self):
delegate(self, Base, object.__init__)
print 'base'

class Left(Base):
def __init__(self):
delegate(self, Left, Base.__init__)
print 'left'

class Right(Base):
def __init__(self):
delegate(self, Right, Base.__init__)
print 'right'

class Der(Left, Right):
def __init__(self):
delegate(self, Der, Left.__init__)
delegate(self, Der, Right.__init__)
print 'der'

der = Der()
 
Reply With Quote
 
 
 
 
Thomas Guettler
Guest
Posts: n/a
 
      12-17-2004
Am Fri, 17 Dec 2004 02:17:38 -0600 schrieb Robert Dick:

> Derived classes sometimes need to delegate portions of the work in overridden
> methods to methods in their base classes. This was traditionally done with
> explicit calls in python, e.g.,
>
> class Base:
> def __init__(self):
> print 'base'
>
> class Left(Base):
> def __init__(self, arg):
> Base.__init__(self)
> print 'left'
>
> class Right(Base):
> def __init__(self, arg):
> Base.__init__(self)
> print 'right'


If you can change the source of Base, I would do it like
this:

class Base:
_init_done=0
def __init__(self):
if self._init_done:
return
self._init_done=1

# ... do init


Thomas

--
Thomas GŁttler, http://www.thomas-guettler.de/


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
delegation question, where I want prototype style delegation Sam Roberts Ruby 4 05-07-2008 05:48 AM
prototype __proto__ super and delegation cbare Javascript 1 11-01-2007 06:28 PM
prototype __proto__ super and delegation cbare Javascript 8 10-31-2007 05:01 PM
super.super.super how? Java 24 02-24-2005 10:51 PM
Getting the super class via the super() function Fernando Rodriguez Python 2 11-22-2003 12:08 AM



Advertisments