Hi all !
I have written a little module called 'polymorph' that allows to call
different methods of a class that have the same name but that have not
the same number of arguments. *args are supported. You could find the
module attached to this message.
As in python, you could not define two method with same name (the second
one override the first one), i have choosen to design it through private
prefix '__' (defined method names and called method name are different).
You just have to put the number of args of your method (without the
'self' one) and use the prefix keyword 'p' (polymorph) or 'pe' (elliptic
method where last argument is '*args').
now an example:
#============== =============== =============== =============== ============
import polymorph
""" You could add polymorphism for your class.
You just have to inherit polymorph.Polym orph class
and prefix your methods that have the same name
but differ from the number of args with the
following prefix :
__<x>p__ where x is the number of args of your method
__<x>pe__ where x is the number of args of your method if you
use elliptic argument at the end (*args)
see below for a little demo class.
Priority : check if __<x>p__... exists before __<x>pe__... for the
same <x>.
"""
class Demo(polymorph. Polymorph):
def __init__(self):
PolymorphicClas s.__init__(self )
def __1p__foo(self, first):
return (first,)
def __2p__foo(self, first,second):
return (first,second)
def __0p__bar(self) :
return ()
def __1pe__bar(self ,*args):
return [args]
def __2p__bar(self, first,second):
return (second,first)
aninstance = Demo()
#print "foo with no parameter : ",aninstance.fo o()
print "foo with 1 parameter : ",aninstance.fo o(3)
print "foo with 2 parameters : ",aninstance.fo o(4,6)
#print "foo with 3 parameters : ",aninstance.fo o(4,6,8)
print "bar with 0 parameter : ",aninstance.ba r()
print "bar with 1 parameter : ",aninstance.ba r(4)
print "bar with 2 parameters : ",aninstance.ba r(9,1)
print "bar with 10 parameters : ",aninstance.ba r(1,2,3,4,5,6,7 ,8,9,0)
#============== =============== =============== =============== ============
returns :
foo with 1 parameter : (3,)
foo with 2 parameters : (4, 6)
bar with 0 parameter : ()
bar with 1 parameter : [(4,)]
bar with 2 parameters : (1, 9)
bar with 10 parameters : [(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)]
I think that this could help to design classes with lesser 'switch'
behavior in all-in-one method with *args argument.
Do you find it useful ?
regards,
rashkatsa
import types,string
""" You could add polymorphism for your class.
You just have to inherit polymorph.Polym orph class
and prefix your methods that have the same name
but differ from the number of args with the
following prefix :
__<x>p__ where x is the number of args of your method
__<x>pe__ where x is the number of args of your method if you use elliptic argument at the end (*args)
for example :
def __1p__spam(self , first)
def __3pe__egg(self ,first,second,* args)
Priority : check if __<x>p__... exists before __<x>pe__... for the same <x>.
author: rashkatsa
send any comments to rashkatsa@wanad oo.fr
"""
# metaclass
class MetaPolymorph:
def __init__(self, name, bases, namespace):
"""Create a new class."""
self.__name__ = name
self.__bases__ = bases
self.__namespac e__ = namespace
def __call__(self):
"""Create a new instance."""
return PolymorphInstan ce(self)
# instance
class PolymorphInstan ce:
def __init__(self, metaclass):
self.__metaclas s__ = metaclass
# simple polymorphic method
self.polymorphi cMethods={}
for pmn in [x for x in self.__metaclas s__.__namespace __.keys() if string.find(x,' p__') != -1 and string.rfind(x[:string.find(x, 'p__')],'__')!=-1 and type(self.__met aclass__.__name space__[x]) is types.FunctionT ype]:
pm = pmn[string.find(pmn ,'p__')+3:]
nbarg=str(pmn[string.rfind(pm n[:string.find(pm n,'p__')],'__')+2:string .find(pmn,'p__' )])
if pm in self.polymorphi cMethods:
self.polymorphi cMethods[pm][nbarg]=self.__metacla ss__.__namespac e__[pmn]
else:
self.polymorphi cMethods[pm]={nbarg:self.__ metaclass__.__n amespace__[pmn]}
# elliptic polymorphic method
self.ePolymorph icMethods={}
for pmn in [x for x in self.__metaclas s__.__namespace __.keys() if string.find(x,' pe__') != -1 and string.rfind(x[:string.find(x, 'pe__')],'__')!=-1 and type(self.__met aclass__.__name space__[x]) is types.FunctionT ype]:
pm = pmn[string.find(pmn ,'pe__')+4:]
nbarg=str(pmn[string.rfind(pm n[:string.find(pm n,'pe__')],'__')+2:string .find(pmn,'pe__ ')])
if pm in self.ePolymorph icMethods:
self.ePolymorph icMethods[pm][nbarg]=self.__metacla ss__.__namespac e__[pmn]
else:
self.ePolymorph icMethods[pm]={nbarg:self.__ metaclass__.__n amespace__[pmn]}
def __getattr__(sel f, name):
polymorphMethod Name=None
try:
value = self.__metaclas s__.__namespace __[name]
except KeyError:
if name in self.polymorphi cMethods.keys() +self.ePolymorp hicMethods.keys ():
polymorphMethod Name=name
else:
raise AttributeError, name
if not polymorphMethod Name:
if type(value) is not types.FunctionT ype:
return value
return BoundMethod(sel f,value)
else:
if name in self.polymorphi cMethods.keys() :
pMethods=self.p olymorphicMetho ds[name]
else:
pMethods=None
if name in self.ePolymorph icMethods.keys( ):
ellipticPMethod s=self.ePolymor phicMethods[name]
else:
ellipticPMethod s=None
return BoundPolymorphM ethods(self,pol ymorphMethodNam e,pMethods,elli pticPMethods)
# bound function with instance == BoundMethod
class BoundMethod:
def __init__(self, instance, function):
self.instance = instance
self.function = function
def __call__(self, *args):
return apply(self.func tion, (self.instance, ) + args)
# bound polymorph functions with instance == BoundPolymorphM ethods
class BoundPolymorphM ethods:
def __init__(self, instance, functionName, functions, ellipticFunctio ns):
self.instance = instance
self.functionNa me=functionName
self.functions = functions
self.ellipticFu nctions=ellipti cFunctions
def __call__(self, *args):
self.func=None
argl=len(args)
try:
self.func = self.functions[str(argl)]
except KeyError:
# try to find an elliptic function
if self.ellipticFu nctions:
# sort the list to find the min-max elliptic function that could be called
sortedKeys=[int(x) for x in self.ellipticFu nctions.keys()]
sortedKeys.sort ()
sortedKeys.reve rse()
keyFound=None
# (x-1) because *args could be empty : ()
for x in sortedKeys:
if argl >= (x-1):
keyFound=str(x)
break
if keyFound:
self.func=self. ellipticFunctio ns[keyFound]
if not self.func:
if argl < 1:
errorMsg='Error : Unknown polymorphic method '+self.function Name+' with no argument'
elif argl == 1:
errorMsg='Error : Unknown polymorphic method '+self.function Name+' with 1 argument'
else:
errorMsg='Error : Unknown polymorphic method '+self.function Name+' with '+str(len(args) )+' arguments'
raise errorMsg
return apply(self.func , (self.instance, ) + args)
# create Polymorph class with the metaclass defined above
Polymorph = MetaPolymorph(' Polymorph', (), {})
I have written a little module called 'polymorph' that allows to call
different methods of a class that have the same name but that have not
the same number of arguments. *args are supported. You could find the
module attached to this message.
As in python, you could not define two method with same name (the second
one override the first one), i have choosen to design it through private
prefix '__' (defined method names and called method name are different).
You just have to put the number of args of your method (without the
'self' one) and use the prefix keyword 'p' (polymorph) or 'pe' (elliptic
method where last argument is '*args').
now an example:
#============== =============== =============== =============== ============
import polymorph
""" You could add polymorphism for your class.
You just have to inherit polymorph.Polym orph class
and prefix your methods that have the same name
but differ from the number of args with the
following prefix :
__<x>p__ where x is the number of args of your method
__<x>pe__ where x is the number of args of your method if you
use elliptic argument at the end (*args)
see below for a little demo class.
Priority : check if __<x>p__... exists before __<x>pe__... for the
same <x>.
"""
class Demo(polymorph. Polymorph):
def __init__(self):
PolymorphicClas s.__init__(self )
def __1p__foo(self, first):
return (first,)
def __2p__foo(self, first,second):
return (first,second)
def __0p__bar(self) :
return ()
def __1pe__bar(self ,*args):
return [args]
def __2p__bar(self, first,second):
return (second,first)
aninstance = Demo()
#print "foo with no parameter : ",aninstance.fo o()
print "foo with 1 parameter : ",aninstance.fo o(3)
print "foo with 2 parameters : ",aninstance.fo o(4,6)
#print "foo with 3 parameters : ",aninstance.fo o(4,6,8)
print "bar with 0 parameter : ",aninstance.ba r()
print "bar with 1 parameter : ",aninstance.ba r(4)
print "bar with 2 parameters : ",aninstance.ba r(9,1)
print "bar with 10 parameters : ",aninstance.ba r(1,2,3,4,5,6,7 ,8,9,0)
#============== =============== =============== =============== ============
returns :
foo with 1 parameter : (3,)
foo with 2 parameters : (4, 6)
bar with 0 parameter : ()
bar with 1 parameter : [(4,)]
bar with 2 parameters : (1, 9)
bar with 10 parameters : [(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)]
I think that this could help to design classes with lesser 'switch'
behavior in all-in-one method with *args argument.
Do you find it useful ?
regards,
rashkatsa
import types,string
""" You could add polymorphism for your class.
You just have to inherit polymorph.Polym orph class
and prefix your methods that have the same name
but differ from the number of args with the
following prefix :
__<x>p__ where x is the number of args of your method
__<x>pe__ where x is the number of args of your method if you use elliptic argument at the end (*args)
for example :
def __1p__spam(self , first)
def __3pe__egg(self ,first,second,* args)
Priority : check if __<x>p__... exists before __<x>pe__... for the same <x>.
author: rashkatsa
send any comments to rashkatsa@wanad oo.fr
"""
# metaclass
class MetaPolymorph:
def __init__(self, name, bases, namespace):
"""Create a new class."""
self.__name__ = name
self.__bases__ = bases
self.__namespac e__ = namespace
def __call__(self):
"""Create a new instance."""
return PolymorphInstan ce(self)
# instance
class PolymorphInstan ce:
def __init__(self, metaclass):
self.__metaclas s__ = metaclass
# simple polymorphic method
self.polymorphi cMethods={}
for pmn in [x for x in self.__metaclas s__.__namespace __.keys() if string.find(x,' p__') != -1 and string.rfind(x[:string.find(x, 'p__')],'__')!=-1 and type(self.__met aclass__.__name space__[x]) is types.FunctionT ype]:
pm = pmn[string.find(pmn ,'p__')+3:]
nbarg=str(pmn[string.rfind(pm n[:string.find(pm n,'p__')],'__')+2:string .find(pmn,'p__' )])
if pm in self.polymorphi cMethods:
self.polymorphi cMethods[pm][nbarg]=self.__metacla ss__.__namespac e__[pmn]
else:
self.polymorphi cMethods[pm]={nbarg:self.__ metaclass__.__n amespace__[pmn]}
# elliptic polymorphic method
self.ePolymorph icMethods={}
for pmn in [x for x in self.__metaclas s__.__namespace __.keys() if string.find(x,' pe__') != -1 and string.rfind(x[:string.find(x, 'pe__')],'__')!=-1 and type(self.__met aclass__.__name space__[x]) is types.FunctionT ype]:
pm = pmn[string.find(pmn ,'pe__')+4:]
nbarg=str(pmn[string.rfind(pm n[:string.find(pm n,'pe__')],'__')+2:string .find(pmn,'pe__ ')])
if pm in self.ePolymorph icMethods:
self.ePolymorph icMethods[pm][nbarg]=self.__metacla ss__.__namespac e__[pmn]
else:
self.ePolymorph icMethods[pm]={nbarg:self.__ metaclass__.__n amespace__[pmn]}
def __getattr__(sel f, name):
polymorphMethod Name=None
try:
value = self.__metaclas s__.__namespace __[name]
except KeyError:
if name in self.polymorphi cMethods.keys() +self.ePolymorp hicMethods.keys ():
polymorphMethod Name=name
else:
raise AttributeError, name
if not polymorphMethod Name:
if type(value) is not types.FunctionT ype:
return value
return BoundMethod(sel f,value)
else:
if name in self.polymorphi cMethods.keys() :
pMethods=self.p olymorphicMetho ds[name]
else:
pMethods=None
if name in self.ePolymorph icMethods.keys( ):
ellipticPMethod s=self.ePolymor phicMethods[name]
else:
ellipticPMethod s=None
return BoundPolymorphM ethods(self,pol ymorphMethodNam e,pMethods,elli pticPMethods)
# bound function with instance == BoundMethod
class BoundMethod:
def __init__(self, instance, function):
self.instance = instance
self.function = function
def __call__(self, *args):
return apply(self.func tion, (self.instance, ) + args)
# bound polymorph functions with instance == BoundPolymorphM ethods
class BoundPolymorphM ethods:
def __init__(self, instance, functionName, functions, ellipticFunctio ns):
self.instance = instance
self.functionNa me=functionName
self.functions = functions
self.ellipticFu nctions=ellipti cFunctions
def __call__(self, *args):
self.func=None
argl=len(args)
try:
self.func = self.functions[str(argl)]
except KeyError:
# try to find an elliptic function
if self.ellipticFu nctions:
# sort the list to find the min-max elliptic function that could be called
sortedKeys=[int(x) for x in self.ellipticFu nctions.keys()]
sortedKeys.sort ()
sortedKeys.reve rse()
keyFound=None
# (x-1) because *args could be empty : ()
for x in sortedKeys:
if argl >= (x-1):
keyFound=str(x)
break
if keyFound:
self.func=self. ellipticFunctio ns[keyFound]
if not self.func:
if argl < 1:
errorMsg='Error : Unknown polymorphic method '+self.function Name+' with no argument'
elif argl == 1:
errorMsg='Error : Unknown polymorphic method '+self.function Name+' with 1 argument'
else:
errorMsg='Error : Unknown polymorphic method '+self.function Name+' with '+str(len(args) )+' arguments'
raise errorMsg
return apply(self.func , (self.instance, ) + args)
# create Polymorph class with the metaclass defined above
Polymorph = MetaPolymorph(' Polymorph', (), {})
Comment