【问题标题】:Method ignored when subclassing a type defined in a C module子类化 C 模块中定义的类型时忽略的方法
【发布时间】:2016-04-19 19:34:35
【问题描述】:

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

如何让它工作,我必须手动调整我班级的字典?如果我不在字典中添加对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__ 返回了一个实例,我仍然可以用方法和属性填充它。任何人都可以对此有所了解吗?

编辑:我导入的模块是 FreeCAD。 C 基类型定义为there。然后 Vector 是从这个定义中导出的 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 都会返回 p.Xp.Yp.Z 的最后一个点的值,无论在创建实例时传递了什么 x,y,z 参数。 p.x, p.y, p.z 返回预期值。这似乎表明字典在实例之间共享。

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

【问题讨论】:

    标签: python subclassing python-c-api freecad


    【解决方案1】:

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

    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.
    

    【讨论】:

    • 当然,这是我首先尝试的,但我得到了Point3d has no attribute named 'X'。我不明白为什么我必须深入幕后才能做到这一点......
    • @JacquesGaudin:检查你的缩进,然后再试一次。您可能缩进了错误的属性。
    • 感谢您的建议。缩进是正确的,我的文件中的所有空格,但在复制粘贴操作期间受到影响。
    【解决方案2】:

    我在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 类未实现以安全地支持子类化,因此 Py_TPFLAGS_BASETYPE 位设置为零以防止其发生。

    关于不能被子类化的bytes内置类型的情况类似。请参阅此 discussion 以了解 Guido van Rossum 为什么 bytes 不可子类化。

    【讨论】:

    • 我认为这是一个有效的答案,但我建议在新问题中而不是在此处提出后续问题。
    • 对不起,我会在做一些研究后打开一个新问题。
    猜你喜欢
    • 2020-11-24
    • 1970-01-01
    • 1970-01-01
    • 2016-11-21
    • 2019-11-25
    • 2022-01-14
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多