"TypeError: object.__init__() takes no parameters" when subclassing mathutils.Matrix

Hello,

I recently faced an issue with mathutils.Matrix subclassing that seems to be beyond my Python competence, so I’m looking for a little help here. What is weird is that I believe this code already worked previously (ie. in a Blender release older than 2.65), but now I just can’t understand why it fails… I tried to have a look at “mathutils_Matrix.c” but it didn’t help.

In fact it seems impossible to pass a default matrix as a parameter when calling the superclass Matrix.

My code is:

from mathutils import Matrix

class Mat(Matrix):
    """3x3 Matrix"""
    def __init__(self, matrix=((0,0,0),(0,0,0),(0,0,0))):
        Matrix.__init__(self, matrix)

Mat()

Calling it leads to the error message:

Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
  File "<blender_console>", line 4, in __init__
TypeError: object.__init__() takes no parameters

But it IS possible to pass a parameter when creating a new Matrix instance directly though:

Matrix(((0,0,0),(0,0,0),(0,0,0)))
Matrix(((0.0, 0.0, 0.0),
        (0.0, 0.0, 0.0),
        (0.0, 0.0, 0.0)))

Does anyone has an idea about what could be wrong here?

Weird indeed, this doesn’t work either:

from mathutils import Matrix

class Mat(Matrix):
    """3x3 Matrix"""
   def __init__(self, matrix=((0,0,0),(0,0,0),(0,0,0))):
      super().__init__(matrix) # same as super(Matrix, self)

same error, init takes no params

that’s something to be answered by the devs!

Yep, I tried the super() stuff as well after looking at some Python documentation (I have to admit I haven’t heard about the new-style classes VS. old-style classes before) but the result was the same. And since the code that manage the Matrix class is in C we can’t simply have a look at the init function to know the possible parameters…

Thanks for the answer anyhow, CoDEmanX.

What is the best way to get in touch with a dev? I don’t think it’s actually worth a bug report, isn’t it?

IRC, freenode.net #blendercoders pobably

Sorry, I never used IRC, and don’t really feel like getting used to it just for this issue.

Isn’t there any dev on www.blender.org/forum ?

Or any other Python guru here? :slight_smile:

as this might be specific to blender, your best chance is to use IRC…

you may use a webclient like this:
http://webchat.freenode.net/

I was recently still wondering why I couldn’t get this code to work, so I decided to have a look at the Blender code directly and this led me to the answer.

In mathutils_Matrix.c I noticed for “PyTypeObject matrix_Type”, tp_init is not set whereas tp_new is. I came to the conclusion I’d rather have to do it using new instead of init. So simple I couldn’t believe it took me almost one year to figure it out! I made so much attempts, I had to read Python documentation about sub-classing, I even reinstalled an older Blender release that actually behave differently. It was just that… :slight_smile:

This code works:

import bpy
from mathutils import Matrix

class Mat(Matrix):
    """3x3 Matrix"""
    def __new__(cls, matrix=((1,0,0),(0,1,0),(0,0,1))):
        return Matrix.__new__(cls, matrix)
        # return super().__new__(cls, matrix)  # <-- same result using super()

# use the default 3x3 identity matrix
print(Mat())

# user defined matrix
print(Mat(((1,0,0),(0,2,0),(0,0,3))))

good job at figuring this one out!

Do you think tp_init should be defined as well in mathutils’ source?

I can’t really tell… For what I have to do in this example overriding new does everything I need. In fact, from what I understood, there’s nothing init can do that new can’t, though it’s better using init if we don’t actually need new.

It seems that in Python 3 classes are automatically subclass of the “object” superclass. In my first code, Mat is a subclass of Matrix, for which init() is not defined. So the new class Mat.init() passes its parameters to object.init(), but this superclass accepts no parameters. That why the error message was “object.init() takes no parameters”. In the new code, Matrix.new() “absorbs” the parameters from Mat.new(), so object.new() doesn’t fail.

Now I presume the Blender developers haven’t felt the need of having both init and new defined for the Python binding, and I’m not an experienced enough Python user to tell whether allowing init overriding is definitively worth it or would just be a waste of time.

There is a similar question on StackOverflow, which might be of interest (the conclusion is the same as jigebren already reached):

It handles with Panda’s instead, but it’s the Python that matters. Let me just paste it here for reference:

The problem is that in this case, you should be overriding __new__ . It seems panda’s Timestamp is immutable (like datetime that it inherits from) so it’s __init__ method does nothing.

The way you wrote it works fine with python 3. Sub