polymorphism in python

David Bolen db3l at fitlinxx.com
Thu Dec 11 12:00:51 EST 2003


Jay O'Connor <joconnor at cybermesa.com> writes:

> I actually ran into this recently with a Smalltalk application to
> Postgresql.  However, since Smalltalk allows you to add new behavior
> to existing classes; I just added String>>asDBString and
> Number>>asDBString.  So my above code would look like:
> 
>     MyClass>>doSqlStuff:: filedName with: fieldValue
>         formatString := fieldValue asDBString.
> 
> And it would polymophically get the right formatted string without any
> type checking at all.

While you could inject such a method with user defined classes, it's
clearly a problem for built-in types.  But one approach to achieve
something similar in Python would be to define an interface (using a
PEP 246-like approach such as PyProtocols) that contained the
asDBString method, and explicitly adapt the arguments to the SQL
function to that interface.

You could then define (right in the module defining that interface if
you like) very simple adapters for the built-in types that would let
them be used without changing any calling code.  So you could end up
with a module like (I prefer the abstract class version of interfaces):

          - - - - - - - - - - - - - - - - - - - - - - - - -

from protocols import Interface, advise, adapt

class ISQLFieldValue(Interface):
    """Value to be used in a SQL operation"""

    def asDBString(self):
        """Return string representation valid for use in a query"""
        raise NotImplementedError


class SQLAdapterString:
    """Adapter for string types"""
    
    advise(instancesProvide = [ISQLFieldValue],
           asAdapterForTypes = [str,unicode])

    def __init__(self, ob, protocol):
        self.ob = ob

    def asDBString(self):
        return "'%s'" % self.ob

      
class SQLAdapterNumeric:
    """Adapter for numeric types"""

    advise(instancesProvide = [ISQLFieldValue],
           asAdapterForTypes = [int,long])

    def __init__(self, ob, protocol):
        self.ob = ob

    def asDBString(self):
        return str(self.ob)
    

class MyClass:
    
    def doSqlStuff (fieldName, fieldValue):
        formatString = adapt(fieldValue,ISQLFieldValue).asDBString()
        return formatString
        
          - - - - - - - - - - - - - - - - - - - - - - - - -


And once written, other objects could inherit the interface, and/or
other modules could externally define their own adapters for other
data types, and MyClass never needs to change.

-- David




More information about the Python-list mailing list