Multiple constructors

Alex Martelli aleaxit at yahoo.com
Sun Feb 6 04:17:31 EST 2005


Philip Smith <as006d4848 at blueyonder.co.uk> wrote:

> Call this a C++ programmers hang-up if you like.
> 
> I don't seem to be able to define multiple versions of __init__ in my matrix

Indeed, you can never define ``multiple versions'' of the same name in
the same scope: one scope + one name -> one object.

That's what a name (in a given scope, which I won't keep repeating)
MEANS -- in Python as well as in common sense.

> class (ie to initialise either from a list of values or from 2 dimensions
> (rows/columns)).
> 
> Even if Python couldn't resolve the __init__ to use on the basis of argument
> types surely it could do so on the basis of argument numbers???

It could, if it didn't think a name is a name is a name.  By sticking to
resolution JUST BY NAME, instead of by name plus who knows what else,
however, Python gains a lot of conceptual simplicity without any loss of
functionality.  Therefore, it's a great design choice.


> At any rate - any suggestions how I code this????

My preferred suggestion is to accept that one name === one object: you
want two different objects (constructors), give them two different
names.  One, if you wish, can be __init__ -- the other could be a
staticmethod or even better a classmethod.  Or, have two named methods.

class Matrix(object):
    def __init__(self, values):
        " init self from values "
    @classmethod
    def withDimensions(cls, x, y):
        return cls([0.0]*x for i in xrange(y))
    @classmethod
    def fromValues(cls, values):
        return cls(values)

Now, Matrix.withDimensions(3, 4) and Matrix.fromValues([[1,2],[3,4]])
are both available and maximally clear, and the latter you can also call
as Matrix([[1,2],[3,4]]) if you wish.  The advantage of using
classmethod is that if you later go and subclass

class SpecialMatrix(Matrix):
   ...

you can call the classmethods on this subclass and get an instance of
the subclass, which can sometimes be handy -- better than using
staticmethods (or factory functions ``outside the class'') and
``hardwiring'' what class they instantiate.


I don't particularly like the concept of a function or method which does
drastically different things -- I'd rather see one function have ONE
function (taking the second repetition as meaning ``role'', ``task'').
This goes for __init__, too.  Still, if you're keen on the idea, you can
of course have your __init__ take optional arguments, check their
presence and/or type, and whatever other devilry; I just think it's not
a very good design, but it does end up with just the same effect as C++
overloaded constructors, which you seem to like.  If you want to do this
all the time, you could even build appropriate infrastructure for this
task -- a little custom descriptor and metaclass, and/or decorators.
Such infrastructure building is in fact fun and instructive -- as long
as you don't fall into the trap of *using* such complications in
production code, where Python's simplicity rules;-).


Alex
 



More information about the Python-list mailing list