Se si fa riferimento a un singolo attributo di una singola istanza molte volte, un semplice trucco è memorizzarlo in una variabile locale.
Se si desidera un modo per creare a basso costo cloni puro Python, condividere l'oggetto dict con l'oggetto originale:
class CheapClone(object):
def __init__(self, original):
self.__dict__ = original.__dict__
Creazione di una copia del genere costa circa la metà della accesso agli attributi strumentato e attribuiamo le ricerche sono i veloce come al solito.
Potrebbe anche esserci un modo per fare in modo che il mapper crei istanze di una classe non strumentale al posto di quella strumentata. Se ho un po 'di tempo, potrei dare un'occhiata a quanto profondamente radicato sia l'assunto che le istanze popolate siano dello stesso tipo della classe strumentata.
Trovato un modo rapido e sporco che sembra funzionare almeno in qualche modo su 0.5.8 e 0.6. Non l'ho provato con l'ereditarietà o altre caratteristiche che potrebbero interagire male. Inoltre, questo tocca alcune API non pubbliche, quindi fai attenzione alle interruzioni quando cambi le versioni.
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
Esempio di utilizzo:
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
fonte
2010-02-24 02:27:53
Sfortunatamente il modello di utilizzo è costituito da molti calcoli su molti piccoli oggetti, quindi la cache locale non è così utile. L'idea della clonazione suona davvero come la strada da percorrere, grazie per il suggerimento rapido. Il tuo commento finale è esattamente quello che vorrei: chiedi al mapper di creare una classe 'non documentata', perché so che è di sola lettura. – CarlS
Grazie mille! Non vedo l'ora di provarlo. – CarlS
Ho già fatto alcuni lavori iniziali sull'hack dei mapper e le differenze di orario sono incoraggianti. Per un semplice ciclo: for i in xrange (500000): foo = readonlyobj.attr_bar con strumentazione normale: 2.663 sec con sola lettura mod mapper: 0.078 sec Questo è un risultato molto significativo imo, quindi grazie ancora. Sto ancora cercando di capire veramente come funziona e si sta rivelando un ottimo modo per imparare sqlalchemy in un po 'più in profondità. – CarlS