Если вы ссылаетесь на один атрибут одного экземпляра много раз, простой прием - сохранить его в локальной переменной.
Если вы хотите создать дешевый чистый клон Python, поделитесь объектом dict с исходным объектом:
class CheapClone(object):
def __init__(self, original):
self.__dict__ = original.__dict__
Создание такой копии обходится примерно в половину инструментального доступа к атрибутам, а поиск атрибутов выполняется так же быстро, как обычно.
Может также быть способ заставить маппер создавать экземпляры неинструментированного класса вместо инструментированного. Если бы у меня было время, я мог бы взглянуть, насколько глубоко укоренилось предположение, что заполненные экземпляры того же типа, что и инструментированный класс.
Нашел быстрый и грязный способ, который, кажется, хоть как-то работает на 0.5.8 и 0.6. Не проверял его с наследованием или другими функциями, которые могут плохо взаимодействовать. Кроме того, это касается некоторых непубличных API, поэтому остерегайтесь поломок при смене версий.
from sqlalchemy.orm.attributes import ClassManager, instrumentation_registry
class ReadonlyClassManager(ClassManager):
"""Enables configuring a mapper to return instances of uninstrumented
classes instead. To use add a readonly_type attribute referencing the
desired class to use instead of the instrumented one."""
def __init__(self, class_):
ClassManager.__init__(self, class_)
self.readonly_version = getattr(class_, 'readonly_type', None)
if self.readonly_version:
# default instantiation logic doesn't know to install finders
# for our alternate class
instrumentation_registry._dict_finders[self.readonly_version] = self.dict_getter()
instrumentation_registry._state_finders[self.readonly_version] = self.state_getter()
def new_instance(self, state=None):
if self.readonly_version:
instance = self.readonly_version.__new__(self.readonly_version)
self.setup_instance(instance, state)
return instance
return ClassManager.new_instance(self, state)
Base = declarative_base()
Base.__sa_instrumentation_manager__ = ReadonlyClassManager
Пример использования:
class ReadonlyFoo(object):
pass
class Foo(Base, ReadonlyFoo):
__tablename__ = 'foo'
id = Column(Integer, primary_key=True)
name = Column(String(32))
readonly_type = ReadonlyFoo
assert type(session.query(Foo).first()) is ReadonlyFoo