Function Overloading and Python

castironpi at gmail.com castironpi at gmail.com
Mon Feb 25 12:04:31 EST 2008


> 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.
'''



More information about the Python-list mailing list