473,241 Members | 1,475 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,241 software developers and data experts.

polymorphism in python

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.Polymorph 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):
PolymorphicClass.__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.foo()
print "foo with 1 parameter : ",aninstance.foo(3)
print "foo with 2 parameters : ",aninstance.foo(4,6)
#print "foo with 3 parameters : ",aninstance.foo(4,6,8)
print "bar with 0 parameter : ",aninstance.bar()
print "bar with 1 parameter : ",aninstance.bar(4)
print "bar with 2 parameters : ",aninstance.bar(9,1)
print "bar with 10 parameters : ",aninstance.bar(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.Polymorph 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 ra*******@wanadoo.fr
"""

# metaclass
class MetaPolymorph:
def __init__(self, name, bases, namespace):
"""Create a new class."""
self.__name__ = name
self.__bases__ = bases
self.__namespace__ = namespace
def __call__(self):
"""Create a new instance."""
return PolymorphInstance(self)

# instance
class PolymorphInstance:
def __init__(self, metaclass):
self.__metaclass__ = metaclass
# simple polymorphic method
self.polymorphicMethods={}
for pmn in [x for x in self.__metaclass__.__namespace__.keys() if string.find(x,'p__') != -1 and string.rfind(x[:string.find(x,'p__')],'__')!=-1 and type(self.__metaclass__.__namespace__[x]) is types.FunctionType]:
pm = pmn[string.find(pmn,'p__')+3:]
nbarg=str(pmn[string.rfind(pmn[:string.find(pmn,'p__')],'__')+2:string.find(pmn,'p__')])
if pm in self.polymorphicMethods:
self.polymorphicMethods[pm][nbarg]=self.__metaclass__.__namespace__[pmn]
else:
self.polymorphicMethods[pm]={nbarg:self.__metaclass__.__namespace__[pmn]}
# elliptic polymorphic method
self.ePolymorphicMethods={}
for pmn in [x for x in self.__metaclass__.__namespace__.keys() if string.find(x,'pe__') != -1 and string.rfind(x[:string.find(x,'pe__')],'__')!=-1 and type(self.__metaclass__.__namespace__[x]) is types.FunctionType]:
pm = pmn[string.find(pmn,'pe__')+4:]
nbarg=str(pmn[string.rfind(pmn[:string.find(pmn,'pe__')],'__')+2:string.find(pmn,'pe__')])
if pm in self.ePolymorphicMethods:
self.ePolymorphicMethods[pm][nbarg]=self.__metaclass__.__namespace__[pmn]
else:
self.ePolymorphicMethods[pm]={nbarg:self.__metaclass__.__namespace__[pmn]}
def __getattr__(self, name):
polymorphMethodName=None
try:
value = self.__metaclass__.__namespace__[name]
except KeyError:
if name in self.polymorphicMethods.keys()+self.ePolymorphicMe thods.keys():
polymorphMethodName=name
else:
raise AttributeError, name
if not polymorphMethodName:
if type(value) is not types.FunctionType:
return value
return BoundMethod(self,value)
else:
if name in self.polymorphicMethods.keys():
pMethods=self.polymorphicMethods[name]
else:
pMethods=None
if name in self.ePolymorphicMethods.keys():
ellipticPMethods=self.ePolymorphicMethods[name]
else:
ellipticPMethods=None
return BoundPolymorphMethods(self,polymorphMethodName,pMe thods,ellipticPMethods)

# 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.function, (self.instance,) + args)

# bound polymorph functions with instance == BoundPolymorphMethods
class BoundPolymorphMethods:
def __init__(self, instance, functionName, functions, ellipticFunctions):
self.instance = instance
self.functionName=functionName
self.functions = functions
self.ellipticFunctions=ellipticFunctions
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.ellipticFunctions:
# sort the list to find the min-max elliptic function that could be called
sortedKeys=[int(x) for x in self.ellipticFunctions.keys()]
sortedKeys.sort()
sortedKeys.reverse()
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.ellipticFunctions[keyFound]
if not self.func:
if argl < 1:
errorMsg='Error: Unknown polymorphic method '+self.functionName+' with no argument'
elif argl == 1:
errorMsg='Error: Unknown polymorphic method '+self.functionName+' with 1 argument'
else:
errorMsg='Error: Unknown polymorphic method '+self.functionName+' 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', (), {})

Jul 18 '05 #1
7 4514
A very interesting invention... does it work with parameter defaults? Oh,
and IIRC, the word you're looking for is "Function overloading" not
"polymorphism". Polymorphism refers to the ability to have completely
different objects that can be used the same way, which Python always has.
Jul 18 '05 #2
martin z wrote:
A very interesting invention... does it work with parameter defaults? Oh,
and IIRC, the word you're looking for is "Function overloading" not
"polymorphism". Polymorphism refers to the ability to have completely
different objects that can be used the same way, which Python always has.


"Function overloading" is still one form of polymorphism. Polymorphism
as a concept can be approached in different ways, including function
overloading, generic programming and inheritance. Languages like
Python are Smalltalk are very good at implementing polymorphism based
on sending a message to an object and as long as the object understands
the message, it doesn't matter what the object is (part of their dynamic
binding); but they are not as good at overloading based on argument
types (how do you have two methods that have the same name but one takes
a single integer argument and one takes a single string argument?
answer, you have one function with an 'if' decision, or you have two
functions with two different names, breaking the polymorphism, or for
more complex objects you get doule-dispatch involved) . Languages like
C++ and Java restrict polymorphism of objects to those within the
hierarchy, but do allow for polymophism by function overloading; C++ and
Ada also have polymopshim through generic programming (generics in Ada,
templates in C++)

Jul 18 '05 #3
Jay O'Connor wrote:
martin z wrote:
"Function overloading" is still one form of polymorphism.

I'm not completly agree. Indeed, dispatching on arguments' types can be
regarded as polymorphism. However, OP needed to dispatch on *number* of
parameters that seems like classic overloading IMHO

regards,
anton.

Jul 18 '05 #4
anton muhin wrote:
Jay O'Connor wrote:
martin z wrote:
"Function overloading" is still one form of polymorphism.


I'm not completly agree. Indeed, dispatching on arguments' types can
be regarded as polymorphism. However, OP needed to dispatch on
*number* of parameters that seems like classic overloading IMHO

I didn't really address the OP phrasing because I'm not really convinced
that overloading on numbers of parameters is really polymophism either,
I was mostly just addressing the follow up; just pointing out that
function overloading, in general, is one way of implementing polymorphism.

Jul 18 '05 #5
Jay O'Connor <jo******@cybermesa.com> wrote:
Languages like Python [and] Smalltalk [...] are not as good at
overloading based on argument types (how do you have two methods
that have the same name but one takes a single integer argument
and one takes a single string argument?


But how often is it actually useful to do such a thing? I can't
remember the last time I wanted to do something like that in Python.
Did lots of it in C++, but that's more working around the language than
anything else. Can you think of a good example of why you would want to
do something like that in Python?

If your intent is that you could call foo(4) or foo('4'), you could just
write:

def foo (x):
theRealX = int (x)

or you could maybe even do:

def foo (x):
if type(x) == StringType:
do string stuff
else:
do integer stuff

but if you're trying to do either of the above, I suspect you're trying
to write C++ in Python (which is as bad, if not worse, as trying to
write Fortran in Python).
Jul 18 '05 #6
>f your intent is that you could call foo(4) or foo('4'), you could just
write:

def foo (x):
theRealX = int (x)

or you could maybe even do:

def foo (x):
if type(x) == StringType:
do string stuff
else:
do integer stuff

but if you're trying to do either of the above, I suspect you're trying
to write C++ in Python (which is as bad, if not worse, as trying to
write Fortran in Python).


The second example should use the expression:
isinstance(x, str)

and not this:
type(x) == StringType

But as you said, it's best to avoid doing it at all ;)

- Kef

Jul 18 '05 #7
Roy Smith wrote:
Jay O'Connor <jo******@cybermesa.com> wrote:

Languages like Python [and] Smalltalk [...] are not as good at
overloading based on argument types (how do you have two methods
that have the same name but one takes a single integer argument
and one takes a single string argument?
But how often is it actually useful to do such a thing? I can't
remember the last time I wanted to do something like that in Python.


I occasionally run into it when I want to display something where you
can polymorphically ask to display something but how it's displayed
depends on whether it's a number or not. However, it's a failry
contrived example as you can do operator overloading on more than just
strings and integers. Even on objects within a hiearchy. I'm not really
a big fan off it, just that it can be done; and that it's legitamite
polymorphism.
or you could maybe even do:

def foo (x):
if type(x) == StringType:
do string stuff
else:
do integer stuff


Generally, if you are programming to the interface and not to the class
(which is what you are usually doing in OO programming, or should be if
your language allows it) than testing for the actual type of an object
is usually a no-no

Jul 18 '05 #8

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

Similar topics

37
by: Mike Meng | last post by:
hi all, I'm a newbie Python programmer with a C++ brain inside. I have a lightweight framework in which I design a base class and expect user to extend. In other part of the framework, I heavily...
0
by: Carlos Moreira | last post by:
Dear all, How could I use Python polymorphism? Which kind of structures Python give me to use polymorphism? Where can I find specific documentation? Thanks and Best regards. Cadu Moreira
0
by: combinational.logic $ soc-ip.com | last post by:
The following website (http://www.soc-ip.com/weblog) has an example of inheritance, polymorphism, and introspection in Python. The example shows a simple classification system for microprocessors....
10
by: Myster Ious | last post by:
Polymorphism replaces switch statements, making the code more compact/readable/maintainable/OO whatever, fine! What I understand, that needs to be done at the programming level, is this: a...
11
by: Catalin Marinas | last post by:
Hi, Sorry if this was previously discussed but it's something I miss in Python. I get around this using isinstance() but it would be cleaner to have separate functions with the same name but...
7
by: Gabriel Zachmann | last post by:
I understand the Wikipedia article on Polymorphism ( http://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29 ) that it doesn't make sense to talk about polymorphism in a fully dynamically...
2
by: sarathy | last post by:
Hi all, I need a small clarification reg. Templates and Polymorphism. I believe templates is really a good feature, which can be used to implement generic functions and classes. But i doubt...
11
by: chsalvia | last post by:
I've been programming in C++ for a little over 2 years, and I still find myself wondering when I should use polymorphism. Some people claim that polymorphism is such an integral part of C++,...
17
by: Bart Friederichs | last post by:
Hello, I created the following inheritance: class Parent { public: void foo(int i); }; class Child : public Parent {
0
by: abbasky | last post by:
### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...
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
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
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...

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.