如果您多次引用單個實例的單個屬性,一個簡單的技巧就是將其存儲在本地變量中。
如果你想有一個方法來創建便宜的純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