Django信号机制源码分析(观察者模式)

Django信号的实现原理本质是设计模式中的观察者模式,浅谈Python设计模式 -- 观察者模式,也可以叫做发布-订阅模式,信号对象维护一个订阅者列表,当信号被触发时,它会遍历订阅者,依次通知它们。

先来回顾一下信号的定义和使用:

from django.dispatch import receiver, Signal

# 信号定义
node_approved = Signal()

# 信号的注册
@receiver(node_approved)
def on_node_approved(sender, instance, **kwargs):
    print(‘接收到信号’)

# 信号的触发
node_approved.send(sender=xx, instance=yy)

源码分析:

1、先来看receiver这个装饰器:

def receiver(signal, **kwargs):
    """
    A decorator for connecting receivers to signals. Used by passing in the
    signal (or list of signals) and keyword arguments to connect::

        @receiver(post_save, sender=MyModel)
        def signal_receiver(sender, **kwargs):
            ...

        @receiver([post_save, post_delete], sender=MyModel)
        def signals_receiver(sender, **kwargs):
            ...
    """
    def _decorator(func):
        if isinstance(signal, (list, tuple)):
            for s in signal:
                s.connect(func, **kwargs)
        else:
            signal.connect(func, **kwargs)
        return func
    return _decorator

逻辑很简单的一个装饰器,核心是调用Signal信号对象的connect方法,也就是上面举例中的node_approved这个对象的connect方法。

2、接着看Signal 的connect方法:

class Signal:
    def __init__(self, providing_args=None, use_caching=False):
        """
        Create a new signal.
        """
        self.receivers = []
        ...
    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 = weakref.WeakMethod
                receiver_object = receiver.__self__
            receiver = ref(receiver)
            weakref.finalize(receiver_object, self._remove_receiver)

        with self.lock:
            self._clear_dead_receivers()
            if not any(r_key == lookup_key for r_key, _ in self.receivers):
                self.receivers.append((lookup_key, receiver))
            self.sender_receivers_cache.clear()

只看倒数第二行:self.receivers.append((lookup_key, receiver)),如果你了解观察者模式就很好理解这行代码的意图:将被装饰的信号处理函数(on_node_approved)注册到self.recervers属性中,也就是观察者模式中讲的主题维护观察者列表行为。

一旦有了这个观察者列表,那么就很容易做到信号被触发时,通知每个观察者的目的。下面看看源码是怎么实现的:

3、信号触发send源码:

class Signal:
    def __init__(self, providing_args=None, use_caching=False):
        """
        Create a new signal.
        """
        self.receivers = []
        ...
    def _live_receivers(self, sender):
        """
        Filter sequence of receivers to get resolved, live receivers.

        This checks for weak references and resolves them, then returning only
        live receivers.
        """
        ...
        receivers = None
        ...
        for (receiverkey, r_senderkey), receiver in self.receivers:
             if r_senderkey == NONE_ID or r_senderkey == senderkey:
                  receivers.append(receiver)
        ...
        non_weak_receivers = []
        for receiver in receivers:
            if isinstance(receiver, weakref.ReferenceType):
                # Dereference the weak reference.
                receiver = receiver()
                if receiver is not None:
                    non_weak_receivers.append(receiver)
            else:
                non_weak_receivers.append(receiver)
        return non_weak_receivers

    def send(self, sender, **named):
        if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
            return []

        return [
            (receiver, receiver(signal=self, sender=sender, **named))
            for receiver in self._live_receivers(sender)
        ]

send理解起来也不难:遍历self._live_receivers(),依次调用各个receiver。而_live_receivers通过源码也可以看出本质还是遍历前面提到的观察者列表self.recervers属性。

相关推荐

  1. Django信号机制分析观察模式

    2023-12-28 10:30:04       63 阅读
  2. C++,观察模式模拟Qt的信号和槽机制

    2023-12-28 10:30:04       36 阅读
  3. django中实现观察模式

    2023-12-28 10:30:04       48 阅读
  4. 观察模式 Observer

    2023-12-28 10:30:04       60 阅读
  5. 观察模式学习

    2023-12-28 10:30:04       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-28 10:30:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-28 10:30:04       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-28 10:30:04       82 阅读
  4. Python语言-面向对象

    2023-12-28 10:30:04       91 阅读

热门阅读

  1. 基数(Radix)排序

    2023-12-28 10:30:04       53 阅读
  2. C# LINQ

    C# LINQ

    2023-12-28 10:30:04      44 阅读
  3. MySQL8 一键部署

    2023-12-28 10:30:04       50 阅读
  4. etcd故障节点

    2023-12-28 10:30:04       50 阅读
  5. SpringBoot集成etcd,实现实时监听,实现配置中心

    2023-12-28 10:30:04       63 阅读
  6. Ubuntu安装WordPress并使用Nginx作为Web服务器

    2023-12-28 10:30:04       58 阅读
  7. Illegal unit of measure (pt inserted)

    2023-12-28 10:30:04       61 阅读
  8. linux和windows获取RAM全局瞬时占用

    2023-12-28 10:30:04       49 阅读