Django 소스 기초 16-django에서 신호에 대한 학습 분석을 깊이 학습하다

5387 단어
django에서 비교적 재미있는 기술이 하나 있다.그것이 신호의 귀속과 수용 기술이다.
프로젝트 개발의 측면에서django의 신호 처리 기술은 보조 기능에 속한다.절차가 뚜렷하지 않다.
django가 제공하는 신호는
class_prepared = Signal(providing_args=["class"])

pre_init = Signal(providing_args=["instance", "args", "kwargs"])
post_init = Signal(providing_args=["instance"])

pre_save = Signal(providing_args=["instance", "raw", "using", "update_fields"])
post_save = Signal(providing_args=["instance", "raw", "created", "using", "update_fields"])

pre_delete = Signal(providing_args=["instance", "using"])
post_delete = Signal(providing_args=["instance", "using"])

post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"])

m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set", "using"])
request_started = Signal()
request_finished = Signal()
got_request_exception = Signal(providing_args=["request"])

신호의 원리를 분석하다.알 수 있어.
신호 내부에서는 주로 Receiver와sender (None 허용) 의 키 조합을 통해 신호 슬롯을 저장합니다.
send가 신호를 보낼 때신호조 목록을 옮겨다니다.sender가 허용할지 여부를 판단합니다.허용되면 함수를 호출합니다.
한 가지 확실한 것은 신호가 단일 방식을 사용한다는 것이다.전체적인 유일성을 가져야 한다는 얘기다.너무 많이 사용하면 성능에 부담이 된다.그렇기 때문에 Django가 자체로 가지고 있는 것만 실현하면 된다.
다음은 뽑아낸 프레젠테이션 코드입니다.
from django.dispatch import saferef
import weakref

def _make_id(target):
    if hasattr(target, '__func__'):
        return (id(target.__self__), id(target.__func__))
    return id(target)

import threading
WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)

class Signal(object):

    def __init__(self):
        self.receivers = []
        self.lock = threading.Lock()

    def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
        import inspect
        assert callable(receiver) , "Signal receivers must be callable."

        try:
            argspec = inspect.getargspec(receiver.__call__)
        except (TypeError, AttributeError):
            argspec = None
        if argspec:
            assert argspec[2] is not None, \
                    "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:
            receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)

        with self.lock:
            for r_key, _ in self.receivers:
                if r_key == lookup_key:
                    break
            else:
                self.receivers.append((lookup_key, receiver))

    def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
        if dispatch_uid:
            loopup_key = (dispatch_uid, _make_id(sender))
        else:
            loopup_key = (_make_id(receiver), _make_id(sender))

        with self.lock:
            for index in xrange(len(self.receivers)):
                (r_key, _) = self.receivers[index]
                if r_key == loopup_key:
                    del self.receivers[index]
                    break

    def has_listeners(self, sender=None):
        return bool(self._live_receivers(_make_id(sender)))

    def send(self, sender, **named):
        responses = []
        if not self.receivers:
            return responses

        for receiver in self._live_receivers(_make_id(sender)):
            response = receiver(signal=self, sender=sender, **named)
            responses.append((receiver, response))
        return responses

    def _live_receivers(self, senderkey):
        none_senderkey = _make_id(None)
        receivers = []

        for (receiverKey, r_senderkey), receiver in self.receivers:
            if r_senderkey == none_senderkey or r_senderkey == senderkey:
                if isinstance(receiver, WEAKREF_TYPES):
                    receiver = receiver()
                    if receiver is not None:
                        receivers.append(receiver)
                else:
                    receivers.append(receiver)
        return receivers

    def _remove_receiver(self, receiver):
        with self.lock:
            to_remove = []
            for key, connected_receiver in self.receivers:
                if connected_receiver == receiver:
                    to_remove.append(key)
            for key in to_remove:
                last_idx = len(self.receivers) - 1
                for idx, (r_key, _)  in enumerate(reversed(self.receivers)):
                    if r_key == key:
                        del self.receivers[last_idx - idx]



signal_demo = Signal()

def reset_queries(**kwargs):
    print 'reset_querys [%s]' % str(kwargs)
signal_demo.connect(reset_queries)

class objDemo(object):
    def click(self):
        signal_demo.send(sender=self.__class__, request={"1":1})

obj = objDemo()
obj.click()

출력 인쇄
reset_querys [{'signal': <__main__.Signal object at 0x109be5290>, 'request': {'1': 1}, 'sender': <class '__main__.objDemo'>}]

좋은 웹페이지 즐겨찾기