Метод игнорируется при создании подкласса типа, определенного в модуле C

Я подклассифицирую тип, определенный в модуле 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 определен там. Тогда вектор получается из этого определения здесь

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.X, p.Y а также p.Z не важно что x,y,z параметры были переданы при создании экземпляра. p.x, p.y, p.z вернуть ожидаемые значения. Кажется, это указывает на то, что словарь распределяется между экземплярами.

РЕДАКТИРОВАТЬ 3: проблема решена! Бит Py_TPFLAGS_BASETYPE установлен в ноль, чтобы предотвратить создание подклассов, как объяснено в ответе ниже.

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 встроенный тип, который нельзя разделить на подклассы. Смотрите это обсуждение, чтобы услышать от Гвидо ван Россума, почему bytes не подкласс

Я не понимаю, почему вы хотите добавить свойства динамически. Просто используйте:

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.
Другие вопросы по тегам