FAQ
I have a personal project that has an elegant solution that requires
both true multiple inheritance of classes (which pretty much limits my
language choices to C++ and Python) and type-based function
overloading.

Now, while this makes it sound like I have to resign myself to C++,
which I am not a fan of writing, I have resisted thus far. Who wants
to manage their own memory? No, I have fallen in love with Python, and
so come asking for help.

I have a very large multiple inheritance tree that will be frequently
extended as my project goes on. Let us call these "type A" classes.

I also have a moderately sized single inheritance tree whose task is
to match sets of "type A" parameters in a function. Let us call these
"type B" classes. "Type Bs" have one function, which is extended with
each new child, and overloaded to match varying combinations of "Type
As." The reason for this is code-reuse and eventual matching with
common "type A" parents.

Now, what are my options in Python to dispatch unique code based on
the permutations of "type A" classes without code repetition?
Such as, where in C++...

class B
{
fun(A x, A y, A z)...
fun(A1 x, A y, A z)...
}

class B1
{
fun(A1 x, A y, A z)...
}

Such that any previous behavior is inherited, but behaves
polymorphically because of the single function name.

B1.fun(A(x), A(y), A(z)) == B.fun(A(x), A(y), A(z))
but
B1.fun(A1(x), A(y), A(z) != B.fun(A1(x), A(y), A(z))

Is there a data-structure solution or third party module that would
mimic this behavior?

PEP 3124 got my hopes up, but I was let down when it was deferred.

Thank you for your time.

Search Discussions

  • Stefan Behnel at Feb 25, 2008 at 7:44 am

    Allen Peloquin wrote:
    class B
    {
    fun(A x, A y, A z)...
    fun(A1 x, A y, A z)...
    }

    class B1
    {
    fun(A1 x, A y, A z)...
    }

    Such that any previous behavior is inherited, but behaves
    polymorphically because of the single function name.
    Try something like this:

    class B(object):
    def fun(x,y,z):
    if isinstance(x, A1):
    return self._fun(x,y,z)
    # ...

    def _fun(x,y,z):
    # ...

    class B1(B):
    def _fun(x,y,z):
    # ...


    Stefan
  • Stefan Behnel at Feb 25, 2008 at 7:46 am

    Stefan Behnel wrote:
    Allen Peloquin wrote:
    class B
    {
    fun(A x, A y, A z)...
    fun(A1 x, A y, A z)...
    }

    class B1
    {
    fun(A1 x, A y, A z)...
    }

    Such that any previous behavior is inherited, but behaves
    polymorphically because of the single function name.
    Try something like this:

    class B(object):
    def fun(x,y,z):
    if isinstance(x, A1):
    return self._fun(x,y,z)
    # ...

    def _fun(x,y,z):
    # ...

    class B1(B):
    def _fun(x,y,z):
    # ...
    Oh, well, make that:

    class B(object):
    def fun(self, x,y,z):
    if isinstance(x, A1):
    return self._fun(x,y,z)
    # ...

    def _fun(self, x,y,z):
    # ...

    class B1(B):
    def _fun(self, x,y,z):
    # ...


    (but you already knew that anyway, didn't you?)

    Stefan
  • Allen Peloquin at Feb 25, 2008 at 7:48 am

    On Feb 24, 11:44 pm, Stefan Behnel wrote:
    Allen Peloquin wrote:
    class B
    {
    fun(A x, A y, A z)...
    fun(A1 x, A y, A z)...
    }
    class B1
    {
    fun(A1 x, A y, A z)...
    }
    Such that any previous behavior is inherited, but behaves
    polymorphically because of the single function name.
    Try something like this:

    class B(object):
    def fun(x,y,z):
    if isinstance(x, A1):
    return self._fun(x,y,z)
    # ...

    def _fun(x,y,z):
    # ...

    class B1(B):
    def _fun(x,y,z):
    # ...

    Stefan
    The problem is that I want to reuse the code of the parent classes
    through inheritance, otherwise this would work fine.

    I am aware that because of the dynamic typing of Python, there
    currently is no type-based function overloading, so I'm looking for
    alternate solutions to my design problem.
  • Stefan Behnel at Feb 25, 2008 at 8:04 am

    Allen Peloquin wrote:
    On Feb 24, 11:44 pm, Stefan Behnel wrote:
    Allen Peloquin wrote:
    class B
    {
    fun(A x, A y, A z)...
    fun(A1 x, A y, A z)...
    }
    class B1
    {
    fun(A1 x, A y, A z)...
    }
    Such that any previous behavior is inherited, but behaves
    polymorphically because of the single function name.
    Try something like this:

    class B(object):
    def fun(x,y,z):
    if isinstance(x, A1):
    return self._fun(x,y,z)
    # ...

    def _fun(x,y,z):
    # ...

    class B1(B):
    def _fun(x,y,z):
    # ...

    Stefan
    The problem is that I want to reuse the code of the parent classes
    through inheritance, otherwise this would work fine.
    Ok, I didn't see you were going to add new subtypes, that makes it more tricky
    to dispatch in the superclass.

    An alternative would be a more generic dispatcher pattern then:

    class B(object):
    _func_implementations = {}
    _dispatch = _func_implementations.get

    def func(self, x,y,z):
    self._dispatch(type(x), self._func)(self,x,y,z)

    def _func(self, x,y,z):
    # ...

    class B1(B):
    def _func(self, x,y,z):
    # ...

    B._func_implementations[B1] = B1._func

    Or, you could dispatch based on type /names/:

    class B(object):
    def func(self, x,y,z):
    func = getattr(self, "_%s_func" % type(x).__name__, self._func)
    func(x,y,z)

    def _A_func(self, x,y,z):
    # ...

    class B1(B):
    def _A1_func(self, x,y,z):
    # ...

    Stefan
  • Gerald Klix at Feb 25, 2008 at 8:50 am

    Stefan Behnel schrieb:
    Allen Peloquin wrote:
    On Feb 24, 11:44 pm, Stefan Behnel wrote:
    Allen Peloquin wrote:
    class B
    {
    fun(A x, A y, A z)...
    fun(A1 x, A y, A z)...
    }
    class B1
    {
    fun(A1 x, A y, A z)...
    }
    Such that any previous behavior is inherited, but behaves
    polymorphically because of the single function name.
    Try something like this:

    class B(object):
    def fun(x,y,z):
    if isinstance(x, A1):
    return self._fun(x,y,z)
    # ...

    def _fun(x,y,z):
    # ...

    class B1(B):
    def _fun(x,y,z):
    # ...

    Stefan
    The problem is that I want to reuse the code of the parent classes
    through inheritance, otherwise this would work fine.
    Ok, I didn't see you were going to add new subtypes, that makes it more tricky
    to dispatch in the superclass.

    An alternative would be a more generic dispatcher pattern then:

    class B(object):
    _func_implementations = {}
    _dispatch = _func_implementations.get

    def func(self, x,y,z):
    self._dispatch(type(x), self._func)(self,x,y,z)

    def _func(self, x,y,z):
    # ...

    class B1(B):
    def _func(self, x,y,z):
    # ...

    B._func_implementations[B1] = B1._func

    Or, you could dispatch based on type /names/:

    class B(object):
    def func(self, x,y,z):
    func = getattr(self, "_%s_func" % type(x).__name__, self._func)
    func(x,y,z)

    def _A_func(self, x,y,z):
    # ...

    class B1(B):
    def _A1_func(self, x,y,z):
    # ...

    Stefan
    The BDFL came across that problem, too. You will find his thoughts here:
    <http://www.artima.com/weblogs/viewpost.jsp?thread1605>
    The reference implementation for his solution is here:
    <http://svn.python.org/view/sandbox/trunk/overload/>

    HTH,
    Gerald
  • Paul Rudin at Feb 25, 2008 at 7:54 am

    Allen Peloquin <tandonmiir at gmail.com> writes:

    I have a personal project that has an elegant solution that requires
    both true multiple inheritance of classes (which pretty much limits my
    language choices to C++ and Python) and type-based function
    overloading.
    Common Lisp :/
  • Bruno Desthuilliers at Feb 25, 2008 at 9:00 am

    Allen Peloquin a ?crit :
    I have a personal project that has an elegant solution that requires
    both true multiple inheritance of classes (which pretty much limits my
    language choices to C++ and Python) and type-based function
    overloading.

    Now, while this makes it sound like I have to resign myself to C++,
    which I am not a fan of writing, I have resisted thus far. Who wants
    to manage their own memory? No, I have fallen in love with Python, and
    so come asking for help. (snip)
    Now, what are my options in Python to dispatch unique code based on
    the permutations of "type A" classes without code repetition?
    There are at least a couple type- or rule- based dispatch packages or
    receipes around. Googling for 'generic' or 'ruledispatch' etc... might
    give you a start.
  • Carl Banks at Feb 25, 2008 at 12:48 pm

    On Feb 25, 2:33 am, Allen Peloquin wrote:
    I have a personal project that has an elegant solution that requires
    both true multiple inheritance of classes (which pretty much limits my
    language choices to C++ and Python) and type-based function
    overloading.

    Now, while this makes it sound like I have to resign myself to C++,
    which I am not a fan of writing, I have resisted thus far. Who wants
    to manage their own memory? No, I have fallen in love with Python, and
    so come asking for help.

    I have a very large multiple inheritance tree that will be frequently
    extended as my project goes on. Let us call these "type A" classes.

    I also have a moderately sized single inheritance tree whose task is
    to match sets of "type A" parameters in a function. Let us call these
    "type B" classes. "Type Bs" have one function, which is extended with
    each new child, and overloaded to match varying combinations of "Type
    As." The reason for this is code-reuse and eventual matching with
    common "type A" parents.

    Now, what are my options in Python to dispatch unique code based on
    the permutations of "type A" classes without code repetition?
    Such as, where in C++...

    class B
    {
    fun(A x, A y, A z)...
    fun(A1 x, A y, A z)...

    }

    class B1
    {
    fun(A1 x, A y, A z)...

    }

    Such that any previous behavior is inherited, but behaves
    polymorphically because of the single function name.

    B1.fun(A(x), A(y), A(z)) == B.fun(A(x), A(y), A(z))
    but
    B1.fun(A1(x), A(y), A(z) != B.fun(A1(x), A(y), A(z))

    Is there a data-structure solution or third party module that would
    mimic this behavior?

    PEP 3124 got my hopes up, but I was let down when it was deferred.

    Thank you for your time.
    At risk of sounding snarky, I'll first advise:

    "Use different names for different expected types."

    Presumably you know what types you're passing in when you write the
    calling function, so you'd also know which variant of the function
    you'd be calling. Might as well just use separate names then.


    But you don't want to do that, and you might have good reasons. So,
    secondly I will advise:

    "Use different names inside the class, and have one function in the
    base class dispatch as necessary."

    class B(object):
    def fun(x,y,z):
    if type(x) == "A":
    return _fun_A(x,y,z)
    if type(x) == "A1":
    return _fun_A1(x,y,z)

    def _fun_A(x,y,z):
    # you know x is of type A

    def _fun_A1(x,y,z):
    # you know x is of type A1

    class B1(B):
    def _fun_A(x,y,z):
    # overrides B._fun_A


    In other words, subclasses only override _fun_type variants. fun is
    left alone. Extend idea as needed for your needs.



    Carl Banks
  • Castironpi at Feb 25, 2008 at 3:27 pm

    On Feb 25, 1:33?am, Allen Peloquin wrote:
    I have a personal project that has an elegant solution that requires
    both true multiple inheritance of classes (which pretty much limits my
    language choices to C++ and Python) and type-based function
    overloading.

    Now, while this makes it sound like I have to resign myself to C++,
    which I am not a fan of writing, I have resisted thus far. Who wants
    to manage their own memory? No, I have fallen in love with Python, and
    so come asking for help.

    I have a very large multiple inheritance tree that will be frequently
    extended as my project goes on. Let us call these "type A" classes.

    I also have a moderately sized single inheritance tree whose task is
    to match sets of "type A" parameters in a function. Let us call these
    "type B" classes. "Type Bs" have one function, which is extended with
    each new child, and overloaded to match varying combinations of "Type
    As." The reason for this is code-reuse and eventual matching with
    common "type A" parents.

    Now, what are my options in Python to dispatch unique code based on
    the permutations of "type A" classes without code repetition?
    Such as, where in C++...

    class B
    {
    ? ? fun(A x, A y, A z)...
    ? ? fun(A1 x, A y, A z)...

    }

    class B1
    {
    ? ? fun(A1 x, A y, A z)...

    }

    Such that any previous behavior is inherited, but behaves
    polymorphically because of the single function name.

    B1.fun(A(x), A(y), A(z)) == B.fun(A(x), A(y), A(z))
    but
    B1.fun(A1(x), A(y), A(z) != B.fun(A1(x), A(y), A(z))

    Is there a data-structure solution or third party module that would
    mimic this behavior?

    PEP 3124 got my hopes up, but I was let down when it was deferred.

    Thank you for your time.
    Does the decorator solution work in this case?

    class B:
    @multimethod( A, A, A )
    def fun( x, y, z )
    @multimethod( A1, A, A )
    def fun( x, y, z )

    class B1:
    @multimethod( A1, A, A )
    def fun( x, y, z )

    b= B1()
    b.fun( A(), A(), A() ) -> B.fun#.1
    b.fun( A1(), A(), A() ) -> B1.fun#.2
  • Castironpi at Feb 25, 2008 at 5:04 pm

    B1.fun(A(x), A(y), A(z)) == B.fun(A(x), A(y), A(z))
    but
    B1.fun(A1(x), A(y), A(z) != B.fun(A1(x), A(y), A(z))

    Is there a data-structure solution or third party module that would
    mimic this behavior?
    '''
    An Overloaded instance, B.xfun, is created in the base class of the
    classes the members of which you want to override. Define the
    function you want to override, merely to call 'invoke' on it.
    xfun.make( typeA, typeB ) is a wrapper which will bind the type-
    function pair to it as well. Define any number of these. When the
    class is complete, call B.xfun.push with the class just defined, to
    let xfun know that the methods just bound were defined in it. Perhaps
    future Pythons will allow a class currently being executed to be
    referenced. Class decorators will be able to permit this as well:
    @xfun.push / class B1( B ). (Anyone know why I got this: "TypeError:
    cannot create 'NoneType' instances"?)

    Upon calling B().fun( A(), A(), A() ), B.fun, the root of all funs,
    calls dispatch on the instance. In theory it could be called directly
    with the right binding. Dispatch then checks the types of the
    arguments, and tries successively higher subclass types on the class
    instance, until it finds a combination of types that was defined. If
    none is found, raise a TypeError. If you want a behavior to occur by
    default, without a matching type sequence, let me know; or do it
    yourself, either with a try: except: combination in B.fun, the
    dispatcher for the bound method, or by testing for a match in it, upon
    succeeding, call that, and upon failing, do the default.
    '''

    class A: pass
    class A1: pass

    class Overloaded:
    def __init__( self ):
    self._tps= {}
    self._pend= {}
    def make( self, *tps ):
    def _pre( func ):
    self._pend[ tps ]= func
    return func
    return _pre
    def dispatch( self, objself, *a ):
    tps= tuple( type( i ) for i in a )
    for c in objself.__class__.__mro__:
    if ( c, )+ tps in self._tps:
    match= self._tps[ ( c, )+ tps ]
    return match( objself, *a )
    raise TypeError( 'No matching type'
    'signature for %s %s types %s %s'%
    ( objself, a, type( objself ), tps ) )
    def push( self, tp ):
    for k, v in self._pend.items():
    self._tps[ ( tp, )+ k ]= v
    self._pend.clear()

    class B:
    xfun= Overloaded()
    def fun( self, *a ):
    return self.xfun.dispatch( self, *a )
    @xfun.make( A, A, A )
    def q( self, x, y, z ):
    return 'B AAA'
    @xfun.make( A1, A, A )
    def q( self, x, y, z ):
    return 'B A1AA'
    B.xfun.push( B )

    class B1(B):
    @B.xfun.make( A1, A, A )
    def q( self, x, y, z ):
    return 'B1 A1AA'
    B.xfun.push( B1 )

    class B2(B1):
    @B.xfun.make( A, A, A )
    def q( self, x, y, z ):
    return 'B2 AAA'
    B.xfun.push( B2 )

    class B3(B1):
    @B.xfun.make( A1, A, A )
    def q( self, x, y, z ):
    return 'B3 A1AA'
    B.xfun.push( B3 )

    b= B()
    assert b.fun( A(), A(), A() )== 'B AAA'
    assert b.fun( A1(), A(), A() )== 'B A1AA'
    b1= B1()
    assert b1.fun( A1(), A(), A() )== 'B1 A1AA'
    assert b1.fun( A(), A(), A() )== 'B AAA'
    b2= B2()
    assert b2.fun( A1(), A(), A() )== 'B1 A1AA'
    assert b2.fun( A(), A(), A() )== 'B2 AAA'
    b3= B3()
    assert b3.fun( A1(), A(), A() )== 'B3 A1AA'
    assert b3.fun( A(), A(), A() )== 'B AAA'
    try:
    assert b3.fun( A(), A1(), A() )== 'B AAA'
    assert False, 'Type matched incorrectly'
    except TypeError:
    pass
    print( 'Pass.' )

    '''
    This is a somewhat advanced technique.
    If you're not using Python 3.0, let me know, and I'll add inheritance
    arguments to Overloaded.push, to replace .__mro__ in
    Overloaded.dispatch.
    '''
  • Castironpi at Mar 2, 2008 at 10:43 pm

    On Feb 25, 11:04?am, castiro... at gmail.com wrote:
    B1.fun(A(x), A(y), A(z)) == B.fun(A(x), A(y), A(z))
    but
    B1.fun(A1(x), A(y), A(z) != B.fun(A1(x), A(y), A(z))
    Is there a data-structure solution or third party module that would
    mimic this behavior?
    class B:
    ? ?xfun= Overloaded()
    ? ?def fun( self, *a ):
    ? ? ? return self.xfun.dispatch( self, *a )
    ? ?@xfun.make( A, A, A )
    ? ?def q( self, x, y, z ):
    ? ? ? return 'B AAA'
    ? ?@xfun.make( A1, A, A )
    ? ?def q( self, x, y, z ):
    ? ? ? return 'B A1AA'
    B.xfun.push( B )
    You could also call xfun.methods( self ) in B.__init__.
    Overloaded.methods binds the methods specified with xfun.make to the B
    instance. In this case, the effect is,

    self.fun= types.MethodType( self.__class__.[x?]fun, self ) -- I forget
    by now.

    But time is money, and money doesn't grow on trees-- so catch me later
    with your own.

    (A decorator could also do it too-- and just in the base class!)

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedFeb 25, '08 at 7:33a
activeMar 2, '08 at 10:43p
posts12
users7
websitepython.org

People

Translate

site design / logo © 2022 Grokbase