Concrete Factory Pattern syntax?

Benjamin Kaplan benjamin.kaplan at case.edu
Thu Mar 19 20:52:33 EDT 2009


On Thu, Mar 19, 2009 at 6:52 PM, 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'
>
>   def make_parser(which_parser):
>       if(which_parser = 'one'):
>         return One()
>       else:
>          return Two()
>
> # import Parser?
> class One(Parser):
>   def parse:
>       'one implementation'
>
> class Two(Parser):
>   def parse:
>       'another implementation'
>
> 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/
>      __init__.py (maybe?)
>      One.py
>      Two.py
>
> But I'm not clear on how to structure the import statements. I'm a bit
> of a newb wrt python, and I get any number of different errors depending
> on how I arrange the import statements, everything from
>
> AttributeError: 'module' object has no attribute 'make_parser'
> to
> ImportError: cannot import name
> to
> TypeError: Error when calling the metaclass bases
>
> depending on how I use import. Nothing seems to be the correct
> combination. Any help would be much appreciated!
>
> Austin
>
>
This seems to be a good use for a metaclass, though it's tricky to work
around the fact that the new class doesn't exist when the metaclass is
called.To get around this, I have the metaclass add the new Parser to a
"to-do" list.  The metaclass will be called whenever a subclass is created,
so every class that subclasses parser will automatically be added.

BTW, don't create a class and a package with the same name. When you import
Parser, python won't know whether you want Parser.py or Parser/__init__.py.

I'm not very good with metaclasses, so there might be a couple mistakes in
here. Note that this won't work if you run this as the main script because
then you end up with two copies of Parser
(Parser.Parser and __main__.Parser).



class ParserMeta(type) : #the metaclass is called when the class is created
    def __new__(cls, *args) :
        #args = (name, bases, dict). dict has __module__ in it.
        #we don't want to add the base class
        if args[0] != "Parser"  :
            Parser._not_loaded_parsers.append(args)
        return type.__new__(cls, *args)


#note that this is for Python 3.
#for python 2.x do:
#class Parser(object) :
#    __metaclass__ = ParserMeta
class Parser(metaclass=ParserMeta) :
    _not_loaded_parsers = [] #the parsers that aren't loaded yet
    parsers = {} #the list of parsers- names mapped to the class.
    def parse(self) :
        raise NotImplementedError

    @classmethod
    def load(cls) :
    """ This method will add the parsers to the dictionary if they aren't
already in there"""
        while cls._not_loaded_parsers :
            new_parser = cls._not_loaded_parsers.pop()
            mod = __import__(new_parser[2]['__module__'], fromlist=['*'])
            cls.parsers[new_parser[0]] = mod.__dict__[new_parser[0]]

    @classmethod
    def make_parser(cls, which_one) :
        """loads the parsers if necessary and returns the parsers"""
        cls.load()
        return cls.parsers[which_one]()


import modules-that-contain-other-parsers

Parser.load()



>
>
>
>
> --
> http://mail.python.org/mailman/listinfo/python-list
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20090319/309edc62/attachment.html>


More information about the Python-list mailing list