问题:
有很多时候, 我们想拥有一个实例, 但是不增加引用计数. 怎么解决呢?
场景:
- 英雄击打怪物, 如果怪物在受到英雄打击前就死了, 我们可以在英雄的实例里面, 使用一个弱引用来引用怪物, 如果还存在就击打, 不存在就不击打.
- 一般的ui系统都有事件系统, ui上触发一个事件, 然后逻辑层去执行, 如果所执行的对象已经销毁了, 就不再执行, 如果是用python写的脚本里的话, 事件系统一般用的就是弱引用.
代码
import weakref
class MyClass(object):
def __init__(self, name):
self.name = name
obj = MyClass('example')
weak_obj = weakref.ref(obj)
print weak_obj().name
del obj
print weak_obj()
执行结果
一个小的事件系统
import weakref
class Signal(object):
trigger_dict = {}
def connect(self, func):
# 因为weakref.ref()不能直接引用实力的方法,所以我们使用曲线救国的方法
Signal.trigger_dict[id(self)] = {
'obj': weakref.ref(func.im_self),
'func_name': func.__name__
}
def emit(self, *args, **kwargs):
info = Signal.trigger_dict[id(self)]
weak_obj = info['obj']()
if not weak_obj:
print 'obj is not exists'
return
f = getattr(weak_obj, info['func_name'], None)
f and f(*args, **kwargs)
class Monster(object):
def __init__(self):
self.hp = 100
def get_hurt(self, damage):
self.hp -= damage
if self.hp < 0:
print 'dead, delete this instance'
print self.hp
monster = Monster()
beat_signal = Signal()
beat_signal.connect(monster.get_hurt)
beat_signal.emit(40)
beat_signal.emit(40)
beat_signal.emit(40)
del monster
beat_signal.emit(40)
执行结果
非常合理, -20之后, 我们删除了monster
的实例, 然后再执行伤害方法的时候, 就默认给过滤了, 这就是weakref
的功力