«Деинструмент» инстанцированного объекта из sqlalchemy ORM - PullRequest
4 голосов
/ 12 февраля 2010

Есть ли простой способ "деинструировать" инстанцированный класс из ORM в sqlalchemy, т.е. превратить его в обычный объект?

Т.е., предположим, у меня есть класс Worker, который сопоставлен с рабочим столом:

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

mapper(Worker,workers)

где работники - это отраженная таблица, содержащая множество наблюдений. Причина, по которой я хочу это сделать, заключается в том, что такие методы, как worker.earnings (), очень медленные из-за всех накладных расходов sqlalchemy (которые мне не нужны для моего приложения). Например, доступ к self.wage примерно в 10 раз медленнее, чем если бы self.wage был свойством обычного класса.

Ответы [ 2 ]

5 голосов
/ 12 февраля 2010

Если вам нужно навсегда удалить класс, просто избавьтесь от картографа:

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

Инструментарий SQLAlchemy живет как дескриптор свойства объекта класса. Поэтому, если вам нужны отдельные деинструментированные версии объектов, вам нужно создать версию класса, у которой нет дескрипторов в его иерархии типов.

Хорошим способом было бы иметь постоянный подкласс для каждого класса модели и создавать сопоставители для постоянных классов. Вот декоратор класса, который создает для вас подкласс и добавляет его в качестве атрибута класса к оригиналу:

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)

А если у вас есть постоянный объект, вы можете создать его деинструментированную версию, например:

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

Вы можете создать деинструментированную версию прямо так:

detached_worker = Worker.Base()
0 голосов
/ 12 февраля 2010

Если вы знаете имена полей, которые вы хотите, скажем, они есть в списке строк с именем 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, чтобы у класса нового объекта было то же имя, что и у класса, который вы "деинструментируете".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...