[Tutor] "Overloading" methods

Steven D'Aprano steve at pearwood.info
Fri Sep 17 03:00:38 CEST 2010


On Thu, 16 Sep 2010 10:02:18 pm Michael Powe wrote:
> Hello,
>
> Strictly speaking, this isn't overloading a method in the way we do
> it in Java.  But similar.  Maybe.

Ha ha, you sound like me -- I can recognise design patterns, but I have 
no idea what they're called, or why anyone bothers to distinguish 
between the "builder" pattern and the "factory" pattern... the 
difference is too subtle for me.

It sounds like what you're trying to do is a design pattern, or 
combination of patterns.


> I am writing a module for processing web server log files and one of
> the methods I provide is to extract a given query parameter and its
> value.

So you have a module that provides a single log-processing class with a 
single method that extracts query parameters?

If there will only ever be a single instance of the class, you should 
consider making the methods ordinary functions. Instead of:

inst = module.LogProcessor()
inst.extract(stuff)


you get:

module.extract(stuff)


Modules give you Singleton behaviour for free!


> Because there are several types of log files with different 
> line structures, I had the thought to write methods with descriptive
> names that simply returned a generic method that processed the method
> arguments. e.g.,
>
> def setpattern_iis(self,pattern,parameter) :
> 	type='iis'
> 	return pattern_generator(self,type,pattern,parameter)
>
> In this case, creating a regular expression to parse the log lines
> for a query parameter.

Sounds fine to me. I would question the name -- a method 
called "setpattern_iis" should, well, *set* a pattern somewhere (a 
global? a property?), not return a value. But other than that, the 
basic tactic is sound. Whether it is more or less straightforward 
compared to alternatives is another question. (See below.)


> This is just a bit more "self documenting" than using the generic
> method with the 'type' argument and requiring the user to enter the
> type.

True, but consider how the caller might use this. I'm guessing what your 
API might be:

import module
log_parser = module.Log_Parser()  # make a generic parser
regex = logParser.setpattern_iis(pattern, parameter)  # get a regex
results = logParser.search_log(regex, log)  # and use it

Am I close? 

Perhaps a better API might be:

import module
log_parser = module.IIS_Log_Parser()  # make a IIS parser
results = log_parser.search_log(pattern, parameters, log)


In this case, the basic strategy would be to have an abstract log 
parser:

class AbstractLogParser(object):
    type = None

    def __init__(self):
        if self is AbstractLogParser:
            raise TypeError('abstract class cannot be initialised')

    # define common methods
    def pattern_generator(self, pattern, parameter):
        type = self.type
        return type + "spam"  # whatever...

    def search_log(self, pattern, parameters, log):
        regex = self.pattern_generator(pattern, parameter)
        return regex.search(log)  # whatever


Creating a new subclass is easy:

class IISLogParser(AbstractLogParser):
    type = 'iis'



-- 
Steven D'Aprano


More information about the Tutor mailing list