如果你多次引用单个实例的单个属性,一个简单的技巧是将其存储在本地变量中。
如果你想要一种创建廉价纯Python克隆的方法,请与原始对象共享字典对象:
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:
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
for i in xrange(500000): foo = readonlyobj.attr_bar
使用正常的工具:2.663秒 使用只读映射器hack:0.078秒在我看来,这是非常显著的结果,所以再次感谢。我仍在努力真正理解它的工作原理,并且这被证明是学习SQLAlchemy更深入的好方法。 - CarlS