如果多次引用单个实例的单个属性,一个简单的技巧是将其存储在局部变量中。
如果你想要一种创建廉价的纯 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