如果您多次引用单个实例的单个属性,一个简单的技巧就是将其存储在本地变量中。
如果你想有一个方法来创建便宜的纯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:
# 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
不幸的是,使用模式是许多小对象的许多计算,所以本地缓存并不是那么有用。克隆想法听起来像是要走的路,感谢快速提示。您的最终评论正是我想要的:请映射器创建一个“未经修复”的类,因为我知道它是只读的。 – CarlS 2010-02-24 03:42:26
非常感谢!我迫不及待想尝试一下。 – CarlS 2010-02-24 05:49:12
我已经完成了关于mapper hack的一些初步工作,并且时间差异令人鼓舞。对于一个简单的循环: 因我的xrange(500000):富= readonlyobj.attr_bar 正常仪器:2.663秒 与只读映射黑客:0.078秒 国际海事组织(IMO)是一个非常显著的结果,所以再次感谢。我仍然试图真正理解它是如何工作的,这证明了一个更深入学习sqlalchemy的好方法。 – CarlS 2010-03-02 04:18:12