2016-04-19 30 views
5

Sto sottoclassi un tipo definito in un modulo C per alias alcuni attributi e metodi in modo che il mio script funzioni in diversi contesti.Metodo ignorato quando sottoclasse un tipo definito in un modulo C

Come è possibile che per farlo funzionare, devo modificare manualmente il dizionario della mia classe? Se non aggiungo un riferimento a DistanceTo nel dizionario, ottengo 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) 

pensavo che una volta __new__ erano tornati un'istanza ho potuto ancora compilarlo con i metodi e gli attributi. Qualcuno può far luce su questo?

MODIFICA: il modulo che importa da è FreeCAD. Il tipo di base C è definito there. Poi Vector deriva forma questa definizione here

EDIT2: Ho provato anche il seguente:

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) 

e dopo aver creato un secondo punto, sia Point3D p restituisce il valore dell'ultimo punto per p.X, p.Y e p.Z non importa quali siano stati passati i parametri x,y,z durante la creazione dell'istanza. p.x, p.y, p.z restituiscono i valori previsti. Sembra indicare che il dizionario è condiviso tra le istanze.

EDIT 3: problema risolto! Il bit Py_TPFLAGS_BASETYPE è impostato su zero per impedire la sottoclasse come spiegato nella risposta seguente.

risposta

1

ho trovato la risposta in 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. 
*/ 

Ciò è dovuto alla classe App::VectorPy non in corso di attuazione per sostenere in modo sicuro sottoclassi e quindi il bit Py_TPFLAGS_BASETYPE è impostato a zero per impedirlo dall'accaduto.

Per informazioni, si tratta di una situazione simile al tipo integrato bytes che non può essere sottoclasse. Vedi questo discussion per ascoltare Guido van Rossum perché bytes non è sottoclassi.

+0

Penso che questa sia una risposta valida ma ti consiglierei di porre domande di follow-up in una nuova domanda invece di qui. – MSeifert

+0

Scusate, aprirò una nuova domanda dopo aver fatto un po 'di ricerche. –

2

Non capisco perché si voglia aggiungere le proprietà dinamicamente. Basta usare:

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. 
+0

Assolutamente, questo è quello che ho provato prima, ma ho ottenuto un 'Point3d non ha alcun attributo chiamato 'X''. Non capisco perché devo andare sotto il cofano per fare questo ... –

+1

@JacquesGaudin: Controlla il tuo indentation e riprova. Probabilmente hai indentato le proprietà sbagliate. – user2357112

+0

Grazie per aver suggerito questo. Il rientro è corretto, tutti gli spazi nel mio file ma sono stati danneggiati durante l'operazione di copia-incolla. –