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

Method ignored when subclassing a type defined in a C module

我正在对 C 模块中定义的类型进行子class,以对某些属性和方法进行别名,以便我的脚本在不同的上下文中工作。

为什么我必须手动调整 class 的字典才能让它工作?如果我不在字典中添加对 DistanceTo 的引用,我会得到 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)

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

编辑:我从中导入的模块是 FreeCAD。 C 基类型定义为 there. Then Vector is derived form this definition here

EDIT2:我也试过以下方法:

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)

并且在创建第二个点后,Point3d p returns 都为 p.Xp.Yp.Z 的最后一个点的值 no不管在创建实例时传递了什么 x,y,z 参数。 p.x, p.y, p.z return 预期值。这似乎表明字典是在实例之间共享的。

编辑 3:问题已解决! Py_TPFLAGS_BASETYPE 位设置为零以防止 subclassing,如下面的答案所述。

我不明白你为什么要动态添加属性。只需使用:

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.

我在 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.
 */

这是由于 App::VectorPy class 没有被实施以安全地支持 subclassing,因此 Py_TPFLAGS_BASETYPE 位被设置为零以防止它发生。

供参考,这与无法被子class的bytes内置类型类似。请参阅此 discussion 以听听 Guido van Rossum 为什么 bytes 不是 subclassable。