首页 > 编程 > Python > 正文

深入理解Django-Signals信号量

2020-02-16 01:13:37
字体:
来源:转载
供稿:网友

定义Signals

Django自身提供了一些常见的signal,用户本身也可以定义自己需要的signal

定义signal很简单,只需要实例化一个Signal实例即可

实例化Signal时,可以传入关键词参数providing_args, providing_args是一个列表,列表中定义了当前signal调用send方法时可以传入的参数。

# django.core.signals.pyfrom django.dispatch import Signalrequest_started = Signal(providing_args=["environ"])request_finished = Signal()got_request_exception = Signal(providing_args=["request"])setting_changed = Signal(providing_args=["setting", "value", "enter"])

其中Signal的初始化也比较简单,就是为实例化的signal定义一个线程锁

class Signal(object):  def __init__(self, providing_args=None, use_caching=False):    self.receivers = []    if providing_args is None:      providing_args = []    self.providing_args = set(providing_args)    self.lock = threading.Lock()    self.use_caching = use_caching    # For convenience we create empty caches even if they are not used.    # A note about caching: if use_caching is defined, then for each    # distinct sender we cache the receivers that sender has in    # 'sender_receivers_cache'. The cache is cleaned when .connect() or    # .disconnect() is called and populated on send().    self.sender_receivers_cache = weakref.WeakKeyDictionary() if use_caching else {}    self._dead_receivers = False

定义Signal处理函数

Signal处理函数是一个函数或者是一个实例的方法,并且必须满足下面条件:

    hashable 可以接收关键词参数

其中处理函数必须包含的关键词参数有两个:

signal,要接收的Signal实例 sender,要接收的Signal触发者
# django.db.__init__.pyfrom django.core import signalsfrom django.db.utils import ConnectionHandlerconnections = ConnectionHandler()def reset_queries(**kwargs):  for conn in connections.all():    conn.queries_log.clear()signals.request_started.connect(reset_queries)def close_old_connections(**kwargs):  for conn in connections.all():    conn.close_if_unusable_or_obsolete()signals.request_started.connect(close_old_connections)signals.request_finished.connect(close_old_connections)

处理函数绑定Signal

django提供了两种方法可以将Signal的处理函数和Signal实例进行绑定:

手动调用connect方法 使用装饰器receiver

其实装饰器receiver最终还是调用了connect方法将处理函数和Signal实例进行绑定

Signal类的connect方法定义如下:

class Signal(object):  ...    def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):    from django.conf import settings    # If DEBUG is on, check that we got a good receiver    if settings.configured and settings.DEBUG:      assert callable(receiver), "Signal receivers must be callable."      # Check for **kwargs      if not func_accepts_kwargs(receiver):        raise ValueError("Signal receivers must accept keyword arguments (**kwargs).")    if dispatch_uid:      lookup_key = (dispatch_uid, _make_id(sender))    else:      lookup_key = (_make_id(receiver), _make_id(sender))    if weak:      ref = weakref.ref      receiver_object = receiver      # Check for bound methods      if hasattr(receiver, '__self__') and hasattr(receiver, '__func__'):        ref = WeakMethod        receiver_object = receiver.__self__      if six.PY3:        receiver = ref(receiver)        weakref.finalize(receiver_object, self._remove_receiver)      else:        receiver = ref(receiver, self._remove_receiver)    with self.lock:      self._clear_dead_receivers()      for r_key, _ in self.receivers:        if r_key == lookup_key:          break      else:        self.receivers.append((lookup_key, receiver))      self.sender_receivers_cache.clear()            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表