Philip Smith said:
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