[Tutor] Re: How can I avoid cut'n'paste in this case?

Nigel Rowe tutor.fisheggs at xoxy.net
Sun Apr 17 02:03:05 CEST 2005


Kent Johnson wrote:

> Nigel Rowe wrote:
>> I have two modules, both define the same set of classes (with differing
>> implementations) and a number of utility functions that use those
>> classes.
>> 
>> The utility functions are identical (the differences I need are
>> abstracted in the classes), so they are cut'n'pasted into both files.
>> 
>> A simplified concrete example (not what I'm doing, but it illustrates the
>> point):
>> 
>> -- C.py --
>> |class Comment:
>> |    def __init__(self, value):
>> |        self.value = value
>> |
>> |    def __str__(self):
>> |        return "/* " + self.value + " */"
>> |
>> |# utility functions
>> |import time
>> |def stamp():
>> |    return Comment(time.asctime())
>> 
>> 
>> -- P.py --
>> |class Comment:
>> |    def __init__(self, value):
>> |        self.value = value
>> |
>> |    def __str__(self):
>> |        return "# " + self.value + "\n"
>> |
>> |# utility functions
>> |import time
>> |def stamp():
>> |    return Comment(time.asctime())
>> 
>> 
>> How can I refactor these modules to avoid the code duplication?
> 
> You could make stamp() a classmethod of a common base class like this:
> 
> # CommentBase.py
> import time
> 
> class CommentBase(object):
>      def stamp(cls):  # cls will be one of the Comment implementations
>          return cls(time.asctime())
> 
>      stamp = classmethod(stamp)
> 
> # C.py
> from CommentBase import CommentBase
> class Comment(CommentBase):
>      def __init__(self, value):
>          self.value = value
> 
> 
> # Client code
> from C import Comment
> 
> c = Comment.stamp()  # This becomes CommentBase.stamp(Comment)
> print type(c), c.value
> 
> 
> Kent

Thanks Kent, that's an approach that wouldn't have occurred to me. 
Unfortunately it's not going to do the job for me, since it would require
extensive changes to the client code.

ie.
import C as lang
lang.stamp()

would need to be re-written as

import C as lang
lang.Comment.stamp()

The other problem is that there are a LOT of classes, and some of the
utility functions make use of multiple classes.

eg. (not real code)
class this: ...
class that: ...
class other: ...
class something: ...

def utl_1():
    x = this()
    y = other()
def utl_2():
    z = this()
    foo = something()
def utl_3():
    a = something()
    b = other()

(You get the idea.)

Maybe I'm going too far, trying to eliminate the cut'n'paste, but I've
always thought it a bad smell.

-- 
        Nigel Rowe
        A pox upon the spammers that make me write my address like..
                rho (snail) swiftdsl (stop) com (stop) au



More information about the Tutor mailing list