我们发现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