子类化C模块中定义的类型时忽略的方法

Jac*_*din 5 python python-c-api subclassing freecad

我正在将C模块中定义的类型子类化为别名的一些属性和方法,以便我的脚本在不同的上下文中工作.

如何让它工作,我必须手动调整我班级的字典?如果我没有DistanceTo在dictionnary中添加引用,我会得到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)
Run Code Online (Sandbox Code Playgroud)

我在想,一旦__new__返回了一个实例,我仍然可以用方法和属性填充它.任何人都可以对此有所了解吗?

编辑:我导入的模块是FreeCAD.那里定义了C基类型.然后Vector是衍生形式这个定义在这里

编辑2:我也尝试了以下内容:

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)
Run Code Online (Sandbox Code Playgroud)

并且在创建第二个点之后,Point3d都p返回最后一个点的值p.X,p.Y并且p.Z无论x,y,z在创建实例时传递了什么参数.p.x, p.y, p.z返回预期值.它似乎表明字典是在实例之间共享的.

编辑3:问题解决了!Py_TPFLAGS_BASETYPE位设置为零以防止子类化,如下面的答案中所述.

Jac*_*din 1

我在以下位置找到了答案 PyObjectBase.cpp

/** \brief 
 * To prevent subclasses of PyTypeObject to be subclassed in Python we should remove 
 * the Py_TPFLAGS_BASETYPE flag. For example, the classes App::VectorPy  and App::MatrixPy
 * have removed this flag and its Python proxies App.Vector and App.Matrix cannot be subclassed.
 * In case we want to allow to derive from subclasses of PyTypeObject in Python
 * we must either reimplment tp_new, tp_dealloc, tp_getattr, tp_setattr, tp_repr or set them to
 * 0 and define tp_base as 0.
 */
Run Code Online (Sandbox Code Playgroud)

这是由于该类App::VectorPy未实现安全支持子类化,因此 Py_TPFLAGS_BASETYPE 位设置为零以防止发生这种情况。

bytes仅供参考,这与无法子类化的内置类型的情况类似。请参阅此讨论,了解 Guido van Rossum 为什么bytes不可子类化。