defsend_robust(self,sender,**named):# 相比send方法调用receiver方法异常时直接退出,send_robust会收集异常并返回ifnotself.receiversorself.sender_receivers_cache.get(sender)isNO_RECEIVERS:return[]# Call each receiver with whatever arguments it can accept.# Return a list of tuple pairs [(receiver, response), ... ].responses=[]forreceiverinself._live_receivers(sender):try:response=receiver(signal=self,sender=sender,**named)exceptExceptionaserr:responses.append((receiver,err))# 如果调用receiver出现异常则捕获并返回相应的异常而不影响其他receiver的调用else:responses.append((receiver,response))returnresponses
def_clear_dead_receivers(self):# Note: caller is assumed to hold self.lock.# 清除dead_receiversifself._dead_receivers:self._dead_receivers=False# 还原_dead_receivers为Falseself.receivers=[rforrinself.receiversifnot(isinstance(r[1],weakref.ReferenceType)andr[1]()isNone)# 弱引用,并且该弱引用对应的对象已消亡]
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=Noneifself.use_cachingandnotself._dead_receivers:# 如果使用缓存并且self.receivers中无dead_receiversreceivers=self.sender_receivers_cache.get(sender)# 直接从缓存中获取# We could end up here with NO_RECEIVERS even if we do check this case in# .send() prior to calling _live_receivers() due to concurrent .send() call.# 其实我们在调用_live_receivers方法的send方法中已经检查过一次了ifreceiversisNO_RECEIVERS:return[]ifreceiversisNone:# 如果不使用缓存或者存在待清理的dead receiverswithself.lock:self._clear_dead_receivers()# 先清理dead_receiverssenderkey=_make_id(sender)receivers=[]for(receiverkey,r_senderkey),receiverinself.receivers:# 遍历self.receivers进行查找匹配ifr_senderkey==NONE_IDorr_senderkey==senderkey:# 如果senderkey为id(None)或匹配receivers.append(receiver)# 将receiver(weakref)添加到receivers中# 更新缓存ifself.use_caching:# 如果使用缓存ifnotreceivers:# 如果该sender没有receiver (receivers为空)self.sender_receivers_cache[sender]=NO_RECEIVERS# 将cache中该sender的receivers置为空else:# 如果该sender存在对应的receiver# Note, we must cache the weakref versions.# 注意我们应该缓存弱引用self.sender_receivers_cache[sender]=receivers# 将该sender及其所有的receivers缓存起来non_weak_receivers=[]forreceiverinreceivers:# receivers要么为[] 要么为[receiver]ifisinstance(receiver,weakref.ReferenceType):# Dereference the weak reference.# https://www.kite.com/python/docs/weakref.ReferenceTypereceiver=receiver()# 获取弱引用所指的实际对象,若已消亡则返回None,否则返回对象的强引用(“可直接调用”)ifreceiverisnotNone:# weakref所指的原对象尚未消亡non_weak_receivers.append(receiver)# 添加实际可调用的receiver对象else:non_weak_receivers.append(receiver)# 不是弱引用则直接添加returnnon_weak_receivers# 可调用对象receiver的列表
def_remove_receiver(self,receiver=None):# Mark that the self.receivers list has dead weakrefs. If so, we will# clean those up in connect, disconnect and _live_receivers while# holding self.lock. Note that doing the cleanup here isn't a good# idea, _remove_receiver() will be called as side effect of garbage# collection, and so the call can happen while we are already holding# self.lock.# 标记self.receivers中有dead weakrefs(weakref所指对象已消亡).如果存在dead receiver# 程序会在调用connect, disconnect和_live_receivers时在加锁的情况下清除dead weakrefs# 注意在这里执行具体的清除操作并不是一个好主意,在垃圾回收时_remove_receiver()会被# 自动触发,而我们可能在其他操作中对receivers加了锁,此时清理receivers将会导致冲突self._dead_receivers=True
importthreadingimportweakreffromdjango.utils.inspectimportfunc_accepts_kwargs# 返回对象的id,在connect存储记录和send查询记录时会用到# 注意:sender和receiver都必须是可哈希的def_make_id(target):ifhasattr(target,'__func__'):# 如果是对象方法return(id(target.__self__),id(target.__func__))returnid(target)# django.utils.inspect.func_accepts_kwargs# 检查传入的函数是否接受**kwargs参数deffunc_accepts_kwargs(func):returnany(pforpininspect.signature(func).parameters.values()ifp.kind==p.VAR_KEYWORD)NONE_ID=_make_id(None)# A marker for cachingNO_RECEIVERS=object()classSignal:"""
所有signal的基类
Base class for all signals
Internal attributes:
receivers
{ receiverkey (id) : weakref(receiver) }
"""def__init__(self,providing_args=None,use_caching=False):"""
创建新的signal
providing_args: 在调用send()方法时可以传入这个signal的参数列表
"""self.receivers=[]# ((receiver_id,sender_id),receiver_weakref)或者是((dispatch_id,sender_id),receiverweak_ref)# 具体是强引用还是weakref取决于connect时的weak参数是True还是False# 默认weak为True使用弱引用,若为False则删除该条记录时需要手动disconnectifproviding_argsisNone:providing_args=[]self.providing_args=set(providing_args)self.lock=threading.Lock()# 加锁保证操作数据时线程安全self.use_caching=use_caching# 是否使用缓存# 为了便利即使不使用缓存我们也会创建空的缓存# 关于缓存需要注意的一点是:如果use_caching为True,对于每一个sender# 我们会在sender_receiver_cache中缓存其所有的receiver。# 该缓存在调用.connect()或者.disconnect()时会被清除,而在调用send时会被填充self.sender_receivers_cache=weakref.WeakKeyDictionary()ifuse_cachingelse{}self._dead_receivers=False# receivers属性列表中是否含有“失效”的receiver引用(已被垃圾回收)# 在_clear_dead_receivers方法中会检查其值,如果为True则代表其中# 有失效的receiver引用,则过滤清理一遍receivers属性列表defconnect(self,receiver,sender=None,weak=True,dispatch_uid=None):"""
# 通过signal将receiver连接到sender
Arguments:
receiver
A function or an instance method which is to receive signals.
Receivers must be hashable objects.
If weak is True, then receiver must be weak referenceable.
Receivers must be able to accept keyword arguments.
If a receiver is connected with a dispatch_uid argument, it
will not be added if another receiver was already connected
with that dispatch_uid.
sender
The sender to which the receiver should respond. Must either be
a Python object, or None to receive events from any sender.
weak
Whether to use weak references to the receiver. By default, the
module will attempt to use weak references to the receiver
objects. If this parameter is false, then strong references will
be used.
dispatch_uid
An identifier used to uniquely identify a particular instance of
a receiver. This will usually be a string, though it may be
anything hashable.
"""fromdjango.confimportsettings# If DEBUG is on, check that we got a good receiver# 如果在DEBUG模式下,则检查该receiver是否满足要求ifsettings.configuredandsettings.DEBUG:assertcallable(receiver),"Signal receivers must be callable."# Check for **kwargsifnotfunc_accepts_kwargs(receiver):raiseValueError("Signal receivers must accept keyword arguments (**kwargs).")ifdispatch_uid:lookup_key=(dispatch_uid,_make_id(sender))# 如果设置了dispatch_uid作为某receiver的标识else:lookup_key=(_make_id(receiver),_make_id(sender))# 没有dispatch_uid则使用receiver的idifweak:# 如果使用weak则存储该receiver的弱引用,否则就直接存储强引用(强引用最终需要手动disconnect)ref=weakref.refreceiver_object=receiver# 强引用# Check for bound methodsifhasattr(receiver,'__self__')andhasattr(receiver,'__func__'):# 检查是否是对象方法# https://docs.python.org/zh-cn/3/library/weakref.html#weakref.WeakMethodref=weakref.WeakMethodreceiver_object=receiver.__self__# 包含该对象方法的对象# 使用弱引用替代强引用receiver=ref(receiver)# 普通函数方法则直接取其弱引用# 当receiver方法、或包含该方法对象消亡时从signal的receivers列表中清除该条记录weakref.finalize(receiver_object,self._remove_receiver)# https://docs.python.org/zh-cn/3/library/weakref.html#weakref.finalize# 当receiver对象垃圾回收时调用_remove_receiver置self._dead_receivers = Truewithself.lock:self._clear_dead_receivers()# 清除、过滤dead_receiversifnotany(r_key==lookup_keyforr_key,_inself.receivers):# 查重self.receivers.append((lookup_key,receiver))# 添加((receiver_id,sender_id),receiver_weakref)self.sender_receivers_cache.clear()# 变更后清除缓存defdisconnect(self,receiver=None,sender=None,dispatch_uid=None):"""
将signal中的receiver与sender“断开连接”
该函数主要针对那些在connect时weak参数为False的情况,即signal的receivers列表
中存储的是rceiver的强引用
如果在connect时使用的弱引用(weak=True), 则不需要手动调用disconnect方法
receiver和sender的记录会被自动删除
Arguments:
receiver
The registered receiver to disconnect. May be none if
dispatch_uid is specified.
sender
The registered sender to disconnect
dispatch_uid
the unique identifier of the receiver to disconnect
"""ifdispatch_uid:lookup_key=(dispatch_uid,_make_id(sender))# 如果提供了dispatch_uid则使用其替代 id(receiver)else:lookup_key=(_make_id(receiver),_make_id(sender))disconnected=Falsewithself.lock:self._clear_dead_receivers()# 先清除dead_receiversforindexinrange(len(self.receivers)):(r_key,_)=self.receivers[index]ifr_key==lookup_key:# 根据lookup_key在self.receivers中查找disconnected=Truedelself.receivers[index]# 删除self.receivers中的对应记录breakself.sender_receivers_cache.clear()# 变更后清除缓存returndisconnecteddefhas_listeners(self,sender=None):# 通过调用_live_receivers方法看sender的recivers是否为空returnbool(self._live_receivers(sender))defsend(self,sender,**named):"""
Send signal from sender to all connected receivers.
从sender中发送信号给所有连接到该sender的receiver
If any receiver raises an error, the error propagates back through send,
terminating the dispatch loop. So it's possible that all receivers
won't be called if an error is raised.
Arguments:
sender
The sender of the signal. Either a specific object or None.
named
Named arguments which will be passed to receivers.
Return a list of tuple pairs [(receiver, response), ... ].
"""ifnotself.receiversorself.sender_receivers_cache.get(sender)isNO_RECEIVERS:# 如果该signal得receivers为空或者该sender对应的receivers缓存为空return[]return[(receiver,receiver(signal=self,sender=sender,**named))# 这里的receiver就是具体的receiver函数forreceiverinself._live_receivers(sender)# _live_receiver返回的是receiver的可调用对象(就是具体的receiver函数,强引用)的列表]# 返回[(receiver函数,调用receiver函数的结果)]如果调用某个receiver时发生异常程序会直接退出# 导致其他的剩下的receiver并未被执行defsend_robust(self,sender,**named):"""
Send signal from sender to all connected receivers catching errors.
Arguments:
sender
The sender of the signal. Can be any Python object (normally one
registered with a connect if you actually want something to
occur).
named
Named arguments which will be passed to receivers. These
arguments must be a subset of the argument names defined in
providing_args.
Return a list of tuple pairs [(receiver, response), ... ].
If any receiver raises an error (specifically any subclass of
Exception), return the error instance as the result for that receiver.
相比send方法调用receiver方法异常时直接退出,send_robust会收集异常并返回
"""ifnotself.receiversorself.sender_receivers_cache.get(sender)isNO_RECEIVERS:return[]# Call each receiver with whatever arguments it can accept.# Return a list of tuple pairs [(receiver, response), ... ].responses=[]forreceiverinself._live_receivers(sender):try:response=receiver(signal=self,sender=sender,**named)exceptExceptionaserr:responses.append((receiver,err))# 如果调用receiver出现异常则捕获并返回相应的异常而不影响其他receiver的调用else:responses.append((receiver,response))returnresponsesdef_clear_dead_receivers(self):# Note: caller is assumed to hold self.lock.# 清除dead_receiversifself._dead_receivers:self._dead_receivers=Falseself.receivers=[rforrinself.receiversifnot(isinstance(r[1],weakref.ReferenceType)andr[1]()isNone)# 弱引用,并且该弱引用对应的对象已消亡]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=Noneifself.use_cachingandnotself._dead_receivers:# 如果使用缓存并且self.receivers中无dead_receiversreceivers=self.sender_receivers_cache.get(sender)# 直接从缓存中获取# We could end up here with NO_RECEIVERS even if we do check this case in# .send() prior to calling _live_receivers() due to concurrent .send() call.# 在调用_live_receivers方法的方法中已经检查过一次了ifreceiversisNO_RECEIVERS:return[]ifreceiversisNone:# 如果不使用缓存或者存在待清理的dead receiverswithself.lock:self._clear_dead_receivers()# 先清理dead_receiverssenderkey=_make_id(sender)receivers=[]for(receiverkey,r_senderkey),receiverinself.receivers:# 遍历self.receivers进行查找匹配ifr_senderkey==NONE_IDorr_senderkey==senderkey:# 如果senderkey为id(None)或匹配receivers.append(receiver)# 将receiver(weakref)添加到receivers中# 更新缓存ifself.use_caching:# 如果使用缓存ifnotreceivers:# 如果该sender没有receiver (receivers为空)self.sender_receivers_cache[sender]=NO_RECEIVERS# 将cache中该sender的receivers置为空else:# 如果该sender存在对应的receiver# Note, we must cache the weakref versions.# 注意我们应该缓存弱引用self.sender_receivers_cache[sender]=receivers# 将该sender及其所有的receivers缓存起来non_weak_receivers=[]forreceiverinreceivers:# receivers要么为[] 要么为[receiver]ifisinstance(receiver,weakref.ReferenceType):# Dereference the weak reference.# https://www.kite.com/python/docs/weakref.ReferenceTypereceiver=receiver()# 获取弱引用所指的实际对象,若已消亡则返回None,否则返回对象的强引用(“可直接调用”)ifreceiverisnotNone:# ref所指的原对象尚未消亡non_weak_receivers.append(receiver)# 添加实际可调用的对象else:non_weak_receivers.append(receiver)# 不是弱引用则直接添加returnnon_weak_receivers# 可调用对象receiver的列表def_remove_receiver(self,receiver=None):# Mark that the self.receivers list has dead weakrefs. If so, we will# clean those up in connect, disconnect and _live_receivers while# holding self.lock. Note that doing the cleanup here isn't a good# idea, _remove_receiver() will be called as side effect of garbage# collection, and so the call can happen while we are already holding# self.lock.# 标记self.receivers中有dead weakrefs(weakref所指对象已消亡).如果存在dead receiver# 程序会在调用connect, disconnect和_live_receivers时在加锁的情况下清除dead weakrefs# 注意在这里执行具体的清除操作并不是一个好主意,在垃圾回收时_remove_receiver()会被# 自动触发,而我们可能在其他操作中对receivers加了锁,此时清理receivers将会导致冲突self._dead_receivers=Truedefreceiver(signal,**kwargs):"""
A decorator for connecting receivers to signals. Used by passing in the
signal (or list of signals) and keyword arguments to connect::
用来将receivers连接到对应signal的装饰器. 使用时传入signal(或者是装有signal的列表)
以及相关的关键字参数
@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):ifisinstance(signal,(list,tuple)):# 传入的是signal列表forsinsignal:s.connect(func,**kwargs)# 调用connect方法,sender的信息包含在kwargs中了else:signal.connect(func,**kwargs)returnfuncreturn_decorator