“de-instrument”来自sqlalchemy ORM的实例化对象

时间:2010-02-12 04:36:24

标签: python optimization sqlalchemy

是否有一种简单的方法来“解除”来自sqlalchemy的ORM的实例化类,即将其转换为常规对象?

即,假设我有一个映射到工作表的Worker类:​​

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

mapper(Worker,workers)

其中,工人是包含大量观察结果的反映表。我想这样做的原因是像worker.earnings()这样的方法非常慢,因为所有sqlalchemy开销(我的应用程序不需要)。例如,如果self.wage属于普通级别的财产,那么访问self.wage的速度要慢10倍。

2 个答案:

答案 0 :(得分:5)

如果你需要永久地解除一个类,只需处理映射器:

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

SQLAlchemy检测作为类对象的属性描述符。因此,如果您需要单独的deinstrumented版本的对象,则需要创建一个类的版本,该类在其类型层次结构中没有描述符。

一种好方法是为每个模型类创建一个持久子类,并为持久化类创建映射器。这是一个类装饰器,它为您创建子类,并将其作为类属性添加到原始类:

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

你可以在这样的定义中使用它:

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

mapper(Worker, workers)

当你有一个持久对象时,你可以像这样创建一个denstrumented版本:

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

您可以直接创建一个denstrumented版本:

detached_worker = Worker.Base()

答案 1 :(得分:0)

如果你知道你想要的字段的名称,比如说你有一个名为fields的字符串列表,以及你想要的那些方法,例如你的例子中的earnings,名为methods的字符串列表,然后:

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

您可能希望__name__字符串中包含fields,以便新对象的类与您“去除仪器”的名称相同。