11
\$\begingroup\$

I'm trying to write a Python module to handle matrices. (I know about numpy, this is just for fun)

So far I have written a few classes, Matrix, Dim, and Vec. Matrix and Vec are both subclasses of Dim. When creating a matrix, one would first start out with a list of lists and they would create a matrix like:

startingList = [[1,2,3],[4,5,6],[7,8,9]]
myMatrix = matrix.Matrix(startingList)

This should create a Matrix. The created Matrix should contain multiple Dims all of the same length. Each of these Dims should contain multiple Dims all of the same length, etc. The last Dim, the one that contains numbers, should contain only numbers and should be a Vec instead of a Dim.

So far this works as I want it to. Here is what I have:

from numbers import Number

test2DMat = [[1,2,3],[4,5,6],[7,8,9]]
test3DMat = [[[1,2,3],[4,5,6],[7,8,9]],[[2,3,4],[5,6,7],[8,9,0]],[[9,8,7],[6,5,4],[3,2,1]]]

class Dim(list):
    def __new__(cls,inDim):
        # Make sure inDim is iterable
        iter(inDim)

        # If every item in inDim is a number create a Vec
        if all(isinstance(item,Number) for item in inDim):
            #return Vec(inDim)
            return Vec.__new__(cls,inDim)

        # Make sure every item in inDim is iterable
        try:
            for item in inDim: iter(item)
        except TypeError:
            raise TypeError('All items in a Dim must be iterable')

        # Make sure every item in inDim has the same length
        # or that there are zero items in the list
        if len(set(len(item) for item in inDim)) > 1:
            raise ValueError('All lists in a Dim must be the same length')

        # Actually create the Dim because it passed all the tests
        return list.__new__(cls,inDim)

    def __init__(self,inDim):
        inDim = map(Dim,inDim)
        list.__init__(self,inDim)


class Vec(Dim):
    def __new__(cls,inDim):
        if cls.__name__ not in [Vec.__name__,Dim.__name__]:
            newMat = list.__new__(Vec,inDim)
            newMat.__init__(inDim)
            return newMat
        return list.__new__(Vec,inDim)

    def __init__(self,inDim):
        list.__init__(self,inDim)


class Matrix(Dim):
    def __new__(cls,inMat):
        return Dim.__new__(cls,inMat)

    def __init__(self,inMat):
        super(Matrix,self).__init__(inMat)

This works, but as I have little experience overriding __new__() I'm fairly certain that this could be better. How can I improve this? Answers need not be specific to use of __new__ and __init__, but that is what I care most about.

\$\endgroup\$
4
\$\begingroup\$

First, the thing that was most obvious in your code was that you never used a space after a comma.

Second, you have the Matrix class where you override __new__ and __init__, however it would be work just fine if you'd use class Matrix(Dim): pass.

That's where I started to wonder why you define a Dim class and than inherit from it for Matrix and Vec, instead of code Matrix and subclass Vec from it. Any reason?

I would move the tests from Dim.__new__, except for the numbers test, to __init__. The iter test is not needed, you'll get an error from the list constructor or the for loop anyway.

One issue I see is that Matrix('abc') will result in endless recursion, because strings are iterable. Those are the places where I regret the absence of chr type in python :)

In Vec.__new__, I would let others customize the way they inherit from, why do you check if the class is a Vec or a Dim?

Last tip, when inheriting types like list or str, you have to override all the operator overloading methods if you plan on doing things like Vec((0, 1, 2)) * Vec((2, 3, 4))

Also:

[Vec.__name__,Dim.__name__] use tuples here, memory management

test2DMat = [[1,2,3],[4,5,6],[7,8,9]] I would break lines here

\$\endgroup\$
6
  • \$\begingroup\$ I check if the class is a Vec or Dim (after some modifications I now use isinstance(cls,Dim)) because of how __new__ appears to work. As I stated, I'm not exactly sure how __new__ works, but it sometimes calls __init__ but not always. In my tests __init__ was not getting called for Vec and Dim so I had to manually call it. Things like this are what I was hoping to get feedback on. Is there a better way to do that? \$\endgroup\$
    – Matt
    Oct 19 '12 at 16:34
  • \$\begingroup\$ Matrix.__init__ and Matrix.__new__ are empty in this question as I had not yet gotten around to writing them. I also planned to (and have) added things to Matrix that are not part of Dim. I asked this question before I had written everything I planned to because I mostly cared about the use of __new__ and __init__ and wanted to make sure that was as good as it could be before getting too far into the project. \$\endgroup\$
    – Matt
    Oct 19 '12 at 16:57
  • \$\begingroup\$ "If new__() returns an instance of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to __new__(). If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked.", from docs.python.org/reference/datamodel.html#object.__new \$\endgroup\$
    – unddoch
    Oct 20 '12 at 18:11
  • \$\begingroup\$ Yes, I already had already read that, but my interpretation of it didn't agree with my experience. In code not posted here (a modified version of this) I do not have to call __init__ if I return a Vec and cls is Matrix. Matrix is not an instance of Vec so I would have expected to need to manually call __init__ \$\endgroup\$
    – Matt
    Oct 21 '12 at 18:00
  • \$\begingroup\$ Sounds weird. Could you maybe post the full code? \$\endgroup\$
    – unddoch
    Oct 21 '12 at 18:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.