SALALchemy Session與scoped_session的源碼分析
阿新 • • 發佈:2018-01-13
一次 def mov ans resource with alc set val
我們發現Session與scoped_session都有一些方法:
但是scoped_session的源碼裏面沒有設置這些方法讓我們從源碼裏去窺探下源碼在哪裏設置了這些方法:
Session裏面的方法放在了public_methods裏面:
scoped_session的源碼裏面沒有這些方法?:
那它怎麽實現這些方法的呢?
我們看到了它的構造方法:
def __init__(self, session_factory, scopefunc=None): """Construct a new :class:`.scoped_session`. :param session_factory: a factory to create new :class:`.Session` instances. This is usually, but not necessarily, an instance of :class:`.sessionmaker`. :param scopefunc: optional function which defines the current scope. If not passed, the :class:`.scoped_session` object assumes "thread-local" scope, and will use a Python ``threading.local()`` in order to maintain the current :class:`.Session`. If passed, the function should return a hashable token; this token will be used as the key in a dictionary in order to store and retrieve the current :class:`.Session`.""" self.session_factory = session_factory if scopefunc: self.registry = ScopedRegistry(session_factory, scopefunc) else: self.registry = ThreadLocalRegistry(session_factory)
第一次進來時,scopefunc是空的。
走else,
self.registry = ThreadLocalRegistry(session_factory)
就會實例化:ThreadLocalRegistry。
class ThreadLocalRegistry(ScopedRegistry): """A :class:`.ScopedRegistry` that uses a ``threading.local()`` variable for storage. """ def __init__(self, createfunc): self.createfunc = createfunc self.registry = threading.local()
裏面有兩個對象 self.createfunc和registry:
registry是唯一標識,
session加上括號就會執行__call__方法:
因為self.registry.value第一次進入沒有值:
所以走except 就是執行self.createfunc()往前找傳的值是session_factory那麽session_factory是誰呢?就是我們傳入的session,也就是實例化了我們的session。
就這就會走下面的方法:
def instrument(name): def do(self, *args, **kwargs): return getattr(self.registry(), name)(*args, **kwargs) return do for meth in Session.public_methods: setattr(scoped_session, meth, instrument(meth))
方法二:
我們發現
class scoped_session(object): """Provides scoped management of :class:`.Session` objects. See :ref:`unitofwork_contextual` for a tutorial. """ session_factory = None """The `session_factory` provided to `__init__` is stored in this attribute and may be accessed at a later time. This can be useful when a new non-scoped :class:`.Session` or :class:`.Connection` to the database is needed.""" def __init__(self, session_factory, scopefunc=None): """Construct a new :class:`.scoped_session`. :param session_factory: a factory to create new :class:`.Session` instances. This is usually, but not necessarily, an instance of :class:`.sessionmaker`. :param scopefunc: optional function which defines the current scope. If not passed, the :class:`.scoped_session` object assumes "thread-local" scope, and will use a Python ``threading.local()`` in order to maintain the current :class:`.Session`. If passed, the function should return a hashable token; this token will be used as the key in a dictionary in order to store and retrieve the current :class:`.Session`. """ self.session_factory = session_factory if scopefunc: self.registry = ScopedRegistry(session_factory, scopefunc) else: self.registry = ThreadLocalRegistry(session_factory)
如果我們給
scopefunc傳值就會走if語句,
class ScopedRegistry(object): """A Registry that can store one or multiple instances of a single class on the basis of a "scope" function. The object implements ``__call__`` as the "getter", so by calling ``myregistry()`` the contained object is returned for the current scope. :param createfunc: a callable that returns a new object to be placed in the registry :param scopefunc: a callable that will return a key to store/retrieve an object. """ def __init__(self, createfunc, scopefunc): """Construct a new :class:`.ScopedRegistry`. :param createfunc: A creation function that will generate a new value for the current scope, if none is present. :param scopefunc: A function that returns a hashable token representing the current scope (such as, current thread identifier). """ self.createfunc = createfunc self.scopefunc = scopefunc self.registry = {} def __call__(self): key = self.scopefunc() try: return self.registry[key] except KeyError: return self.registry.setdefault(key, self.createfunc())
我們看到如果對象加括號就會走__call__方法:
第一次沒有值,就會走except,設置並且實例化session。
往下方法和方式一一樣啦。
在執行到最後我們要加上一句:
session.remove()
我們來看下這句話做了什麽?
def remove(self): """Dispose of the current :class:`.Session`, if present. This will first call :meth:`.Session.close` method on the current :class:`.Session`, which releases any existing transactional/connection resources still being held; transactions specifically are rolled back. The :class:`.Session` is then discarded. Upon next usage within the same scope, the :class:`.scoped_session` will produce a new :class:`.Session` object. """ if self.registry.has(): self.registry().close() self.registry.clear()
我們進入has看下:
def has(self): return hasattr(self.registry, "value")
如果有值就執行close方法。
然後在執行clear方法:
def clear(self): try: del self.registry.value except AttributeError: pass
SALALchemy Session與scoped_session的源碼分析