Concrete Factory Pattern syntax?

R. David Murray rdmurray at bitdance.com
Thu Mar 19 21:11:57 EDT 2009


Austin Schutz <tex at off.org> wrote:
> 
> I have a fairly simple bit of code, something like:
> 
> # This should be importing the subclasses somehow, so that the factory
> # can make them.
> # import Parser.One
> # import Parser.Two
> # or.. from Parser import *?
> class Parser():
>    def parse:
> 	'Implemented only in subclass'

Hmm.  You need to go back to the tutorial, I think :)

This should be

    def parse(self):
        raise NotImplementedError

The raise NotImplementedError is the pythonic way of indicating
unimplemented methods in a superclass.  But also take a look
at ABCs (Abstract Base Classes), which provide some nice sugar
for this kind of thing.

>    def make_parser(which_parser):
>        if(which_parser = 'one'):
>          return One()
>        else:
>           return Two()

Skip this, I'll rewrite it later.

> # import Parser?
> class One(Parser):
>    def parse:
>        'one implementation'

Again, 'def parse(self):'.  Might want to make the body something
like "print 'one implementation'" so you can tell if you got
the correct parser when you test it.

> class Two(Parser):
>    def parse:
>        'another implementation'

Same comments as above.

> The problem I have is that I don't understand how to put this into
> actual files in actual directories and have the interpreter do
> something actually useful :-) . What I would like to do is something
> like:
> 
> lib/
>   Parser.py
>   Parser/

Well, there's your first import mistake :).  You can't have a module
and a package both with the same name, nor do you need to.  So drop the
'Parser.py'.  And rename the directory 'parser'; module and package
names are lower case according to the Python style guide.

>       __init__.py (maybe?)

Yes.  Required if you are going to have a package you can import
things from.

>       One.py
>       Two.py

Again, rename these to 'one.py' and 'two.py'.  Then in your
__init__.py file, do:

    from one import One
    from two import Two

Now, in your code that uses the parser, do:

    from parser import One as Parser

or

    from parser import Two as Parser

depending on which parser you want.

Unless your parsers are really heavy, you could probably just
keep all this stuff in one file, parser.py...but if they are complex
enough you want to split the source up, and you want a base class
or ABC, then put that in another file (parserbase.py, perhaps),
and at the top of each of the individual parser files do

    from parserbase import ParserBase

(or some such name).

Now, if you really need the parser to instantiate to be chosen at run
time via a string, you could add something like this to your __init__.py:

    def parserFactory(which_parser):
        return globals()[which_parser.capitalize()]()

which will look up the capitalized version of the string (eg: 'One')
in the __init__.py module's global namespace, thus picking up the
class, and then calls it to create an instance, which is then
returned.

Then your code that uses this can do:

    from parser import parserFactory

    myparser = parserFactory('one')
    
    
>From your class heavy patterns I am guessing you are coming from
Java or some similar language....you don't have to work as hard
to get things done in Python.

--
R. David Murray           http://www.bitdance.com




More information about the Python-list mailing list