子类化 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.X
、p.Y
和 p.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。
我正在对 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.X
、p.Y
和 p.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。