2010-02-12 3 views
4

Existe-t-il un moyen facile de "dés-instrumenter" une classe instanciée provenant de l'ORM de sqlalchemy, c'est-à-dire de le transformer en un objet régulier?"Dés-instrumenter" un objet instancié de sqlalchemy ORM

à savoir, supposons que j'ai une classe de travailleurs qui est mis en correspondance avec une table de travail:

class Worker(object): 
     def earnings(self): 
      return self.wage*self.hours 

mapper(Worker,workers) 

où les travailleurs est une table réfléchie contenant beaucoup d'observations. La raison pour laquelle je veux faire ceci est que les méthodes comme worker.earnings() sont très lentes, à cause de tout le temps système sqlalchemy (dont je n'ai pas besoin pour mon application). Par exemple, l'accès à l'auto-salaire est environ 10 fois plus lent que ce serait si l'auto-salaire était une propriété d'une classe régulière.

Répondre

0

Si vous connaissez les noms des champs que vous voulez, dites que vous avez dans une liste de chaînes appelées fields, et celles des méthodes que vous voulez, comme earnings dans votre exemple, dans une liste de chaînes appelée methods, puis :

def deinstrument(obj, fields, methods): 
    cls = type(obj) 
    class newcls(object): pass 
    newobj = newcls() 
    for f in fields: 
    setattr(newobj, f, getattr(obj, f)) 
    for m in methods: 
    setattr(newcls, m, getattr(cls, m).im_func) 
    return newobj 

vous voudrez probablement __name__ parmi les fields chaînes, de sorte que la nouvelle classe de l'objet a le même nom que celui que vous êtes « de-instrumenter ».

5

Si vous devez deinstrument définitivement une classe, juste en disposer cartographe:

sqlalchemy.orm.class_mapper(Worker).dispose() 

vit instrumentation SQLAlchemy comme descripteurs de propriété sur l'objet de classe. Donc, si vous avez besoin de versions distinctes d'objets, vous devrez créer une version de la classe qui n'a pas les descripteurs dans sa hiérarchie de types.

Un bon moyen serait d'avoir une sous-classe persistante pour chaque classe de modèle et de créer les mappeurs aux classes persistantes. Voici un décorateur de classe qui crée la sous-classe pour vous et ajoute comme un attribut class sur l'original:

def deinstrumentable(cls): 
    """Create a deinstrumentable subclass of the class.""" 
    def deinstrument(self): 
     """Create a non-instrumented copy of the object.""" 
     obj = cls.__new__(cls) 
     obj.__dict__.update(self.__dict__) 
     del obj._sa_instance_state 
     return obj 

    persistent = type('Persisted%s' % cls.__name__, (cls,), { 
     'Base': cls, 
     'deinstrument': deinstrument 
    }) 

    return persistent 

On peut l'utiliser dans la définition comme ceci:

@deinstrumentable 
class Worker(object): 
    def earnings(self): 
     return self.wage*self.hours 

mapper(Worker, workers) 

Et quand vous avez un objet persistant, vous pouvez créer une version deinstrumented de celui-ci comme ceci:

worker = session.query(Worker).first() 
detached_worker = worker.deinstrument() 

vous pouvez créer une version deinstrumented directement comme ceci:

detached_worker = Worker.Base() 
+0

wow que les roches. il h. J'allais dire obj .__ class__ = Foo. – zzzeek

Questions connexes