Class design issues: multiple constructors

Discussion in 'Python' started by Greg Brunet, Aug 7, 2003.

  1. Greg Brunet

    Greg Brunet Guest

    I'm trying to write a package to handle working with DBase files.
    There's enough different stuff in handling them (unfortunately) that I'm
    not going to try to the interface DB-API 2.0 compliant - it'll be a
    lower level wrapper around reading & writing the DBF files. In trying
    to design a good framework, however, I'm unsure of how to progress. I
    intend to have a class to represent the actual DBF files, and I would
    expect to have an __init__ method to be called when creating a new
    instance. When I first started, I included a filename as a parameter
    that would be used to open an existing DBF file. Next I decided to add
    the ability to create a new DBF file. This method needs additional
    parameters (such as the field definitions), and, while in some other
    languages, I could provide 2 versions of the constructor (overload it if
    I'm using the right terminology), and the compiler would use the
    appropriate one, things don't seem to work that way in Python. I'm also
    thinking that I might rather name the methods more specifically (such as
    Open & Create) instead of both being __init__. What would be the
    Pythonic way to go about doing this? Would I make an __init__, Open, &
    Create methods, and make 2 calls for each DBF object, like this:

    class dbf:
    __init__(self):
    pass
    Create(self, filename, fieldDefs):
    pass
    Open(self, filename):
    pass

    # open existing file
    f1 = dbf()
    f1 = dbf.Open('customer.dbf')
    # create a new file
    f2 = dbf()
    f2 = dbf.Create('states.dbf', [('StateCode', 'C', 2), \
    ('StateName','C',20)]


    Or maybe there's a clean way to be able to 'bundle' the
    initialization/construction into the Create & Open method calls. Thanks
    for the help,

    --
    Greg
    Greg Brunet, Aug 7, 2003
    #1
    1. Advertising

  2. Greg Brunet wrote:
    ...
    > instance. When I first started, I included a filename as a parameter
    > that would be used to open an existing DBF file. Next I decided to add
    > the ability to create a new DBF file. This method needs additional
    > parameters (such as the field definitions), and, while in some other
    > languages, I could provide 2 versions of the constructor (overload it if
    > I'm using the right terminology), and the compiler would use the
    > appropriate one, things don't seem to work that way in Python. I'm also
    > thinking that I might rather name the methods more specifically (such as
    > Open & Create) instead of both being __init__. What would be the


    Right. The Pythonic way is to provide "factory functions" that prepare
    and return the object you need. Cosmetically, you may make the factory
    functions part of the class itself, using the staticmethod and classmethod
    built-in types of Python 2.2 and later -- no real need, but some people
    are very keen on this style, so Python now supports it.

    > Pythonic way to go about doing this? Would I make an __init__, Open, &
    > Create methods, and make 2 calls for each DBF object, like this:
    >
    > class dbf:
    > __init__(self):
    > pass
    > Create(self, filename, fieldDefs):
    > pass
    > Open(self, filename):
    > pass


    No, it should rather be something like:

    class dbf(object):
    # no need to define __init__ if it's empty!
    def Create(filename, fieldDefs):
    result = dbf()
    # use filename and fieldDefs to populate 'result' appropriately
    return result
    Create = staticmethod(Create)
    def Open(filename):
    result = dbf()
    # use filename to populate 'result' appropriately
    return result
    Open = staticmethod(Open)


    > # open existing file
    > f1 = dbf()
    > f1 = dbf.Open('customer.dbf')


    No, this wouldn't work with the code you propose; it would with
    the variant I suggest, but the first of these statements is useless
    so you should remove it.

    > # create a new file
    > f2 = dbf()
    > f2 = dbf.Create('states.dbf', [('StateCode', 'C', 2), \
    > ('StateName','C',20)]


    Ditto.


    Alex
    Alex Martelli, Aug 7, 2003
    #2
    1. Advertising

  3. Greg Brunet

    Miki Tebeka Guest

    Hello Greg,

    > When I first started, I included a filename as a parameter
    > that would be used to open an existing DBF file. Next I decided to add
    > the ability to create a new DBF file. This method needs additional
    > parameters (such as the field definitions), and, while in some other
    > languages, I could provide 2 versions of the constructor (overload it if
    > I'm using the right terminology), and the compiler would use the
    > appropriate one, things don't seem to work that way in Python. I'm also
    > thinking that I might rather name the methods more specifically (such as
    > Open & Create) instead of both being __init__. What would be the
    > Pythonic way to go about doing this? Would I make an __init__, Open, &
    > Create methods, and make 2 calls for each DBF object, like this:


    I see two ways:
    1. Module (not class) methods: db = opendb(..), db = createdb(...)
    2. Passing keyword arguments.
    def __init__(selfk, filename, **kw):
    if kw.has_key(create):
    ....

    I vote for the former.

    HTH.
    Miki
    Miki Tebeka, Aug 7, 2003
    #3
  4. Greg Brunet

    Greg Brunet Guest

    Hi Miki:

    > I see two ways:
    > 1. Module (not class) methods: db = opendb(..), db = createdb(...)
    > 2. Passing keyword arguments.
    > def __init__(selfk, filename, **kw):
    > if kw.has_key(create):
    > ....
    >
    > I vote for the former.



    Thanks for the response. I lie the first also - what function is being
    called is more clear than option 2 which would require extra tests
    (depending on how many __init__ variations there are). If I can
    understand the staticmethod stuff that Alex mentioned in his message, I
    may try that path , since I'd like to have the methods actually in the
    class definition, but defining them in the module itself is definitely a
    good option. Thanks,


    --
    Greg
    Greg Brunet, Aug 7, 2003
    #4
  5. "Greg Brunet" <> wrote in message news:<>...
    > I'm trying to write a package to handle working with DBase files.
    > There's enough different stuff in handling them (unfortunately) that I'm
    > not going to try to the interface DB-API 2.0 compliant - it'll be a
    > lower level wrapper around reading & writing the DBF files. In trying
    > to design a good framework, however, I'm unsure of how to progress. I
    > intend to have a class to represent the actual DBF files, and I would
    > expect to have an __init__ method to be called when creating a new
    > instance. When I first started, I included a filename as a parameter
    > that would be used to open an existing DBF file. Next I decided to add
    > the ability to create a new DBF file. This method needs additional
    > parameters (such as the field definitions), and, while in some other
    > languages, I could provide 2 versions of the constructor (overload it if
    > I'm using the right terminology), and the compiler would use the
    > appropriate one, things don't seem to work that way in Python. I'm also
    > thinking that I might rather name the methods more specifically (such as
    > Open & Create) instead of both being __init__. What would be the
    > Pythonic way to go about doing this? Would I make an __init__, Open, &
    > Create methods, and make 2 calls for each DBF object, like this:
    >
    > class dbf:
    > __init__(self):
    > pass
    > Create(self, filename, fieldDefs):
    > pass
    > Open(self, filename):
    > pass
    >
    > # open existing file
    > f1 = dbf()
    > f1 = dbf.Open('customer.dbf')
    > # create a new file
    > f2 = dbf()
    > f2 = dbf.Create('states.dbf', [('StateCode', 'C', 2), \
    > ('StateName','C',20)]
    >


    If I understand you correctly, this could be done with a metaclass
    redefining the __call__ method and invoking Open or Create depending
    on the number of the arguments:

    class MetaTrick(type):
    def __call__(cls,*args):
    nargs=len(args)
    obj=cls.__new__(cls)
    if nargs==1:
    obj.Open(*args)
    elif nargs==2:
    obj.Create(*args)
    else:
    raise 'Wrong number of arguments'

    class dbf:
    __metaclass__=MetaTrick
    def Create(self, filename, fieldDefs):
    print filename,fieldDefs
    def Open(self, filename):
    print filename

    f1 = dbf('customer.dbf')
    f2 = dbf('states.dbf', [('StateCode', 'C', 2),
    ('StateName','C',20)])


    Alternatively, without metaclass, you could redefine the __new__ method
    of the class and use a similar trick.
    HTH,


    Michele
    Michele Simionato, Aug 7, 2003
    #5
  6. Greg Brunet

    Greg Brunet Guest

    Hi Michele

    "Michele Simionato" <> wrote in message
    news:...
    > If I understand you correctly, this could be done with a metaclass
    > redefining the __call__ method and invoking Open or Create depending
    > on the number of the arguments:
    >
    > class MetaTrick(type):
    > def __call__(cls,*args):
    > nargs=len(args)
    > obj=cls.__new__(cls)
    > if nargs==1:
    > obj.Open(*args)
    > elif nargs==2:
    > obj.Create(*args)
    > else:
    > raise 'Wrong number of arguments'
    >
    > class dbf:
    > __metaclass__=MetaTrick
    > def Create(self, filename, fieldDefs):
    > print filename,fieldDefs
    > def Open(self, filename):
    > print filename
    >
    > f1 = dbf('customer.dbf')
    > f2 = dbf('states.dbf', [('StateCode', 'C', 2),
    > ('StateName','C',20)])
    >
    >
    > Alternatively, without metaclass, you could redefine the __new__

    method
    > of the class and use a similar trick.
    > HTH,
    >



    Hmm - I see. That could work in this instance, but could get more
    complex with a different combination of 'constructor' types. Since
    python doesn't seem to handle this overloading for me automatically, I
    don't think that it's worth the effort it to manually implement it -
    it's likely to be a source of more work & errors down the road. I'm
    kind of leaning to using the 'staticmethod' technique that Alex
    mentioned. Thanks for another view on it - that (metaclasses) gives me
    one more technique to use in the future,


    --
    Greg
    Greg Brunet, Aug 7, 2003
    #6
  7. Greg Brunet

    Aahz Guest

    In article <>,
    Miki Tebeka <> wrote:
    >
    >1. Module (not class) methods: db = opendb(..), db = createdb(...)


    Clarification: modules have functions, not methods
    --
    Aahz () <*> http://www.pythoncraft.com/

    This is Python. We don't care much about theory, except where it intersects
    with useful practice. --Aahz
    Aahz, Aug 7, 2003
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dave Rudolf
    Replies:
    12
    Views:
    8,276
    Martijn Lievaart
    Feb 6, 2004
  2. Jeremy Smith
    Replies:
    2
    Views:
    587
    Jeremy Smith
    Aug 3, 2006
  3. Jess
    Replies:
    5
    Views:
    596
    Ron Natalie
    Jun 7, 2007
  4. Peng Yu
    Replies:
    5
    Views:
    393
    Juha Nieminen
    Sep 19, 2008
  5. srp113
    Replies:
    3
    Views:
    465
Loading...

Share This Page