Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method ignored when subclassing a type defined in a C module

I am subclassing a type defined in a C module to alias some attributes and methods so that my script works in different contexts.

How is it that to get this to work, I have to tweak the dictionary of my class manually ? If I don't add a reference to DistanceTo in the dictionnary, I get Point3d has no attribute named DistanceTo.

class Point3d(App.Base.Vector):
      def __new__(cls, x, y, z):
          obj = super(Point3d, cls).__new__(cls)
          obj.x, obj.y, obj.z = x, y, z
          obj.__dict__.update({
               'X':property(lambda self: self.x),
               'Y':property(lambda self: self.y),
               'Z':property(lambda self: self.z),
               'DistanceTo':lambda self, p: self.distanceToPoint(p)})
          return obj
      def DistanceTo(self, p): return self.distanceToPoint(p)

I was thinking that once __new__ had returned an instance I could still populate it with methods and attributes. Can anyone shed some light on this ?

EDIT : The module I import from is FreeCAD. The C base type is defined there. Then Vector is derived form this definition here

EDIT2 : I also tried the following :

class Point3d(App.Base.Vector):
      def __new__(cls, x, y, z):
          obj = super(Point3d, cls).__new__(cls)
          obj.x, obj.y, obj.z = x, y, z
          obj.__dict__.update({
               'X': x, 'Y': y, 'Z': z,
               'DistanceTo':lambda self, p: self.distanceToPoint(p)})
           return obj
       def DistanceTo(self, p): return self.distanceToPoint(p)

and after creating a second point, both Point3d p returns the value of the last point for p.X, p.Y and p.Z no matter what x,y,z parameters were passed at the creation of the instance. p.x, p.y, p.z return the expected values. It seems to indicate that the dictionary is shared between instances.

EDIT 3 : Problem solved ! The Py_TPFLAGS_BASETYPE bit is set to zero to prevent subclassing as explained in the answer below.

like image 935
Jacques Gaudin Avatar asked Oct 18 '22 11:10

Jacques Gaudin


1 Answers

I don't understand why you want to add the properties dynamically. Just use:

class Point3d(App.Base.Vector):
    def __init__(self, x, y, z):
        super().__init__(x, y, z)  # or maybe  super().__init__([x, y, z])

    @property
    def X(self):
        return self[0]  # guessing that App.Base.Vector works like a list

    @property.setter
    def X(self, value):
        self[0] = value

    # Y and Z likewise.
like image 178
kay Avatar answered Nov 02 '22 13:11

kay